我正在使用Zend Framework 2和Doctrine 2开发我的应用程序。
在写注释时,我无法理解mappedBy
和inversedBy
之间的区别。
我什么时候应该使用mappedBy
?
我什么时候应该使用inversedBy
?
我什么时候既不用也不用?
这里有一个例子:
/**
*
* @ORMOneToOne(targetEntity="custModEntityPerson", mappedBy="customer")
* @ORMJoinColumn(name="personID", referencedColumnName="id")
*/
protected $person;
/**
*
* @ORMOneToOne(targetEntity="AuthEntityUser")
* @ORMJoinColumn(name="userID", referencedColumnName="id")
*/
protected $user;
/**
*
* @ORMManyToOne (targetEntity="custModEntityCompany", inversedBy="customer")
* @ORMJoinColumn (name="companyID", referencedColumnName="id")
*/
protected $company;
我做了一个快速搜索,发现了以下内容,但我仍然很困惑:
- 示例1
- 示例2
- 示例3
- mappedBy必须在(双向)关联的反转侧上指定
- invertedBy必须在(双向)关联的拥有方上指定
来自条令文件:
- ManyToOne始终是双向关联的拥有方
- OneToMany总是双向关联的反面
- OneToOne关联的拥有方是具有包含外键的表的实体
请参阅https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html
上面的答案不足以让我理解发生了什么,所以在深入研究之后,我想我有办法解释它,这对那些像我一样努力理解的人来说是有意义的。
invertedBy和mappedBy由内部DOCTRINE引擎使用,以减少SQL查询的数量获取所需信息。需要明确的是,如果您不添加invertedBy或mappedBy,您的代码仍然可以工作,但不会进行优化。
例如,看看下面的类:
class Task
{
/**
* @var int
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORMColumn(name="task", type="string", length=255)
*/
private $task;
/**
* @var DateTime
*
* @ORMColumn(name="dueDate", type="datetime")
*/
private $dueDate;
/**
* @ORMManyToOne(targetEntity="Category", inversedBy="tasks", cascade={"persist"})
* @ORMJoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
}
class Category
{
/**
* @var int
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORMColumn(name="name", type="string", length=255)
*/
private $name;
/**
* @ORMOneToMany(targetEntity="Task", mappedBy="category")
*/
protected $tasks;
}
如果您要运行命令来生成架构(例如,bin/console doctrine:schema:update --force --dump-sql
),您会注意到Category表上没有用于任务的列。(这是因为它上面没有列注释)
这里需要理解的重要一点是,可变任务只是存在的,因此内部条令引擎可以使用上面的参考,即其mappedBy Category。现在不要像我一样在这里感到困惑Category不是指类名,它指的是Task类上名为"protected$Category"的属性。
类似地,在Tasks类上,属性$category提到它是invertedBy="Tasks",注意这是复数,这不是类名的复数,只是因为该属性在category类中被称为"protected$Tasks"。
一旦你理解了这一点,就很容易理解invertedBy和mappedBy在做什么,以及如何在这种情况下使用它们。
在我的例子中,引用外键(如"tasks")的一方总是获得invertedBy属性,因为它需要知道该类上的哪个类(通过targetEntity命令)和哪个变量(invertedBy=)要"向后工作",也就是说,从中获取类别信息。记住这一点的一个简单方法是,具有foreignkey_id的类就是需要具有invertedBy的类。
与category一样,它的$tasks属性(不在表中,记住,它只是用于优化目的的类的一部分)是MappedBy"tasks",这在两个实体之间正式创建了关系,因此原则现在可以安全地使用JOIN SQL语句,而不是两个单独的SELECT语句。如果没有mappedBy,条令引擎将无法从JOIN语句中知道它将在类"Task"中创建什么变量来放置类别信息。
希望这能更好地解释它。
在双向关系中既有拥有方也有相反方
mappedBy:放入双向关系的反面,指实体拥有方的字段
invertedBy:放入双向关系的拥有方,指实体相反侧的字段
与
mappedBy属性与OneToOne、OneToMany或ManyToMany映射声明一起使用。
invertedBy属性与OneToOne、ManyToOne或ManyToMany映射声明一起使用。
注意:双向关系的拥有方,即包含外键的一方。
关于invertedBy和mappedBy在条令文献中的引用有两种:第一链路、第二链路
5.9.1。拥有和反向
对于多对多关联,您可以选择哪个实体是拥有的,哪个实体是相反的一面。从开发人员的角度来看,有一个非常简单的语义规则来决定哪一方更适合作为拥有方。你只需要问问自己,哪个实体负责连接管理,并选择它作为拥有方。
以Article和Tag这两个实体为例。每当你想将文章连接到标签,反之亦然,主要是文章负责这种关系。每当您添加一篇新文章时,您都希望将其与现有或新标签连接起来。您的createarticle表单可能会支持这个概念,并允许直接指定标记。这就是为什么你应该选择文章作为拥有方,因为它使代码更容易理解:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html