inversedBy和mappingBy有什么区别?


102

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

虽然书面方式说明,我无法理解之间的差异mappedByinversedBy

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;

我进行了快速搜索,发现了以下内容,但仍然感到困惑:

Answers:


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

从原则文档中:

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

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


1
奇怪的是,Doctrine文档记录器决定省去了可能是最常用的多对一双向映射的yaml示例!
彼得·伍斯特

4
@PeterWooster,最佳实践是使用注释,因为这样一来,您就可以获得有关实体的所有信息!
Andreas Linden

这也适用于多对多关系。对于那些用户:您可以自己选择多对多关联的所有权。
2015年

5
@AndreasLinden广泛使用并不意味着最佳实践。使用注释即时编写代码的东西永远不会被视为最佳实践,它不是php本机,甚至默认情况下也未包含在所有框架中。将有关实体的所有信息都放在一个地方是一种反论点。因为将所有代码分组到一个地方是一件好事吗?编写过程很痛苦,维护起来很麻烦,并且减少了项目中的组织。最佳实践 ?咄。
JesusTheHun

3
@JesusTheHun您正在比较苹果和梨。“所有代码”与“有关实体的所有信息”非常不同;)
Andreas Linden'December

55

上面的答案不足以让我了解正在发生的事情,因此在深入研究之后,我认为我有一种解释的方式,这对那些像我一样难以理解的人来说是有意义的。

内部DOCTRINE引擎使用inversedBy和maptedBy 来减少为获取所需信息而必须执行的SQL查询数量。要明确的是,如果您不添加inversedBy或mapdBy,您的代码仍然可以使用,但不会进行优化

因此,例如,看下面的类:

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表上没有用于任务的列。(这是因为它上面没有列注释)

这里要了解的重要一点是,可变任务仅在此处,因此内部学说引擎可以使用其上方的引用,该引用表示其mappingBy类别。现在...不要像我以前那样在这里感到困惑... 类别不是指班级名称,它是指Task类上称为“ protected $ category”的属性。

同样,在Tasks类上,属性$ category提到它是inversedBy =“ tasks”,请注意这是复数形式,这不是类名的复数只是因为该属性在Category中被称为“ protected $ tasks”类。

一旦了解了这一点,就很容易了解inversedB和int的作用,以及在这种情况下如何使用它们。

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

与类别相同,其$ tasks属性(不在表中记住,仅为了优化目的,仅是类的一部分)是MappedBy'tasks',这正式在两个实体之间创建了关系,因此该学说现在可以安全地使用使用JOIN SQL语句而不是两个单独的SELECT语句。如果没有mappingBy,则理论引擎将无法从JOIN语句中得知它将在“任务”类中创建什么变量来放置类别信息。

希望这能更好地解释它。


6
对此进行了很好的解释,并感谢您的努力。我来自Laravel Eloquent,来自教义,这对我来说很难理解这里的逻辑。做得好。Category is NOT referring TO THE CLASS NAME, its referring to the property on the Task class called 'protected $category'我所需要的。它不仅解决了我的问题,而且还帮助我理解了。IMO的最佳答案:-)
Alpha

1
我也是来自Eloquent,这对我有很大帮助。我现在唯一的难题是如何为此设置设置器/获取器,我仍在学习有关的知识
Eman

1
是的,这确实很容易,甚至可以使用某些工具自动完成,稍后与我聊天,我可以为您提供帮助
Joseph Astrahan

1
检查这个答案,stackoverflow.com
questions/16629397/…

1
symfony.com/doc/current/doctrine/associations.html,这实际上是更好的学习方法,symfony使用原则,因此它将教给您同样的东西。
约瑟夫·阿斯特拉罕

21

双向关系中既有拥有方又有相反方

appedBy:放入双向关系的反面以引用其拥有的面

inversedBy:放入双向关系的拥有侧

被映射与OneToOne,OneToMany或ManyToMany映射声明一起使用的属性。

inversedBy与OneToOne,多对一,或多对多映射声明使用的属性。

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

关于inversedBy和映射到教义文档中有两个参考: 第一链接第二链接


1
链接已死?
Scaramouche '18

2

5.9.1。拥有和反面

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.