114

我正在使用 Zend Framework 2 和 Doctrine 2 开发我的应用程序。

在编写注释时,我无法理解 和 之间的mappedBy区别inversedBy

我应该什么时候使用mappedBy

我应该什么时候使用inversedBy

我什么时候都不应该使用?

这是一个例子:

 /**
 *
 * @ORM\OneToOne(targetEntity="\custMod\Entity\Person", mappedBy="customer")
 * @ORM\JoinColumn(name="personID", referencedColumnName="id")
 */
protected $person;

/**
 *
 * @ORM\OneToOne(targetEntity="\Auth\Entity\User")
 * @ORM\JoinColumn(name="userID", referencedColumnName="id")
 */
protected $user;

/**
 *
 * @ORM\ManyToOne (targetEntity="\custMod\Entity\Company", inversedBy="customer")
 * @ORM\JoinColumn (name="companyID", referencedColumnName="id")
 */
protected $company;

我快速搜索并找到以下内容,但我仍然感到困惑:

4

4 回答 4

168
  • mappedBy必须在(双向)关联的反面指定
  • 必须在(双向)关联的拥有方指定inversedBy

来自学说文档:

  • ManyToOne 始终是双向关联的拥有方。
  • OneToMany 始终是双向关联的反面。
  • OneToOne 关联的拥有方是具有包含外键的表的实体。

https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html

于 2012-09-19T13:32:37.033 回答
71

上面的答案不足以让我理解发生了什么,所以在深入研究之后,我认为我有一种解释它的方法,这对于像我一样努力理解的人来说是有意义的。

INTERNAL DOCTRINE引擎使用 inversedBy 和 mappedBy来减少为获取所需信息而必须执行的 SQL 查询的数量。要清楚,如果您不添加 inversedBy 或 mappedBy 您的代码仍然可以工作,但不会被优化

例如,看看下面的类:

class Task
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="task", type="string", length=255)
     */
    private $task;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="dueDate", type="datetime")
     */
    private $dueDate;

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="tasks", cascade={"persist"})
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     */
    protected $category;
}

class Category
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity="Task", mappedBy="category")
     */
    protected $tasks;
}

如果您要运行这些类来生成模式(例如,bin/console doctrine:schema:update --force --dump-sql),您会注意到 Category 表上没有用于任务的列。(这是因为它上面没有列注释)

这里要理解的重要一点是变量 tasks 仅存在于其中,因此内部学说引擎可以使用上面的引用,它表示它的 mappedBy 类别。现在...不要像我一样在这里混淆... Category 不是指类名,它指的是 Task 类上称为“受保护的 $category”的属性。

同样,在 Tasks 类上,属性 $category 提到它是 inversedBy="tasks",注意这是复数,这不是类名的复数,而只是因为该属性在 Category 中被称为“受保护的 $tasks”班级。

一旦你理解了这一点,就很容易理解 inversedBy 和 mappedBy 在做什么以及如何在这种情况下使用它们。

在我的示例中,引用外键(如“任务”)的一侧总是获得 inversedBy 属性,因为它需要知道该类上的哪个类(通过 targetEntity 命令)和哪个变量(inversedBy=)才能“向后工作”,以便说话并从中获取类别信息。记住这一点的一种简单方法是,将具有 foreignkey_id 的类是需要具有 inversedBy 的类。

与 category 一样,它的 $tasks 属性(记住,它只是类的一部分用于优化目的)是 MappedBy 'tasks',这在两个实体之间正式创建了关系,因此学说现在可以安全地使用 JOIN SQL 语句而不是两个单独的 SELECT 语句。如果没有 mappedBy,原则引擎不会从 JOIN 语句中知道它将在“Task”类中创建什么变量来放置类别信息。

希望这能更好地解释它。

于 2016-01-04T00:48:02.590 回答
22

在双向关系中既有拥有方也有反方

mappedBy : 放入双向关系的反面来引用它的拥有方

inversedBy : 放入双向关系的拥有方来引用它的反方

mappedBy属性与 OneToOne、OneToMany 或 ManyToMany 映射声明一起使用。

inversedBy属性与 OneToOne、ManyToOne 或 ManyToMany 映射声明一起使用。

注意:双向关系的拥有方包含外键。

在 Doctrine 文档中有两个关于 inversedBy 和 mappedBy 的参考: 第一个链接第二个链接

于 2013-11-20T16:12:38.477 回答
2

5.9.1。拥有方和反向方

对于多对多关联,您可以选择哪个实体是拥有者,哪个实体是反面。从开发人员的角度来看,有一个非常简单的语义规则可以决定哪一方更适合作为拥有方。您只需要问自己,哪个实体负责连接管理,然后选择它作为拥有方。

以文章和标签两个实体为例。每当您想将文章连接到标签时,反之亦然,主要是文章负责这种关系。每当您添加新文章时,您都希望将其与现有或新标签联系起来。您的创建文章表单可能会支持此概念并允许直接指定标签。这就是为什么你应该选择文章作为拥有方,因为它使代码更易于理解:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html

于 2016-09-25T08:20:38.173 回答