【问题标题】:What is the difference between inversedBy and mappedBy?inversedBy 和 mappedBy 有什么区别?
【发布时间】:2012-09-11 17:05:19
【问题描述】:

我正在使用 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;

我快速搜索了一下,发现如下,但我还是一头雾水:

【问题讨论】:

    标签: php doctrine-orm


    【解决方案1】:
    • ma​​ppedBy 必须在(双向)关联的反面上指定
    • inversedBy 必须在(双向)关联的拥有方上指定

    来自学说文档:

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

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

    【讨论】:

    • 奇怪的是,Doctrine 文档记录者决定省略多对一双向映射的 yaml 示例,这可能是最常用的!
    • @PeterWooster,最好的做法是使用注释,因为您可以将有关实体的所有信息集中在一个地方!
    • 这也适用于多对多关系。对于那些:您可以自己选择多对多关联的拥有方。
    • @AndreasLinden 广泛使用并不意味着最佳实践。使用 cmets 动态编写代码的东西永远不能被认为是最佳实践,它不是 php 原生的,甚至默认情况下也不包含在所有框架中。将有关实体的所有信息放在一个地方是一种反论点。从什么时候将所有代码分组到一个地方是一件好事?编写、维护和减少项目中的组织是一种痛苦。最佳实践 ?呵呵。
    • @JesusTheHun 你在比较苹果和梨。 “所有代码”与“关于实体的所有信息”非常不同;)
    【解决方案2】:

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

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

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

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

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

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

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

    希望这能更好地解释它。

    【讨论】:

    • 这解释得很好,感谢您的努力。我从 Laravel Eloquent 来到教义,这对我来说很难理解这里的逻辑。做得好。 Category is NOT referring TO THE CLASS NAME, its referring to the property on the Task class called 'protected $category' 我所需要的。它不仅解决了我的问题,而且帮助我理解。最好的答案 IMO :-)
    • 我也来自 Eloquent,这对我帮助很大。我现在唯一的症结是如何为此设置 setter/getter,我仍在学习其中的技巧
    • 是的,这真的很简单,甚至可以使用一些工具自动化,稍后开始与我聊天,我可以帮助你
    • symfony.com/doc/current/doctrine/associations.html,这实际上是更好的学习,symfony 使用学说,所以它会教你同样的东西。
    【解决方案3】:

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

    ma​​ppedBy : 放入双向关系的反面来引用其拥有的一面

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

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

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

    通知: 包含外键的双向关系的拥有方。

    Doctrine 文档中有两个关于 inversedBy 和 mappedBy 的参考: First Link,Second Link

    【讨论】:

    • 链接失效了?
    【解决方案4】:

    5.9.1。拥有方和反方

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 2013-12-04
      • 2010-10-02
      • 2011-12-12
      • 2010-09-16
      • 2012-03-14
      相关资源
      最近更新 更多