我遇到问题,确保我的对象之间的关系保持一致。我使用的是Doctrine 2,但这可能也适用于其他语言和ORM映射器。
学说说,人际关系有自己的一面和反面。如果使用双向关系,则需要自己确保一致性。基本上不是手段,当关系的一方发生变化时,你手动需要更新另一方。
这是我的例子Foo hasMany Bar
:
class Foo
{
/** @OneToMany(targetEntity="Bar",mappedBy="foo") */
private $bars;
public function addBar($bar)
{
$this->bars[] = $bar;
// Ensure consistency
$bar->setFoo($this);
}
}
class Bar
{
/** @OneToMany(targetEntity="Foo",inversedBy="bars") */
private $foo;
public function setFoo($foo)
{
$this->foo = $foo;
// Ensure consistency
$foo->addBar($this);
}
}
现在显然,上面的代码无法按预期工作。调用Foo::addBar
或Bar::setFoo
时,它将进入无限循环。那么,应该 Foo
和Bar
如何实现,以便按设计工作?
Doctrine 2 “入门”指南中的用户/错误示例仅仅是为了确保addBar
而不是setFoo
中的一致性而绕过问题。
我遇到的问题是,addBar
和setFoo
都必须是公共函数,否则我无法从相关模型中调用它们。但这意味着使用这些对象的开发人员可以使用任一功能来创建新的关系。
我该如何解决这个问题?其他语言和地图制作者如何解决这个问题?
答案 0 :(得分:2)
我不知道其他地图制作者如何解决这个问题,但基本上是在Doctrine 2中......
当他们谈到手册中的“拥有方”时,他们会引用您的代码应该始终用来关联对象的实体。
这主要是一个语义决定:例如,如果您有汽车和轮胎,那么将轮胎添加到汽车$car->addTire($tire);
并且汽车未添加到轮胎$tire->setCar($car);
中是有意义的。
所以拥有实体应该做的是确保关系的一致性。 “非拥有”方应该只设置关联属性。
所以是的,如果您的代码错误地使用非拥有方,则该关系可能最终不一致。但是,这只是脚本执行过程中的一个问题。即使您没有在两端设置关系,它也会在DB中正确存储,因此下次获取数据时,它将以一致的方式在实体之间建立。
答案 1 :(得分:2)
到目前为止,这是我的方法。刚添加了一些支票。
class Foo
{
/** @OneToMany(targetEntity="Bar",mappedBy="foo") */
private $bars;
public function addBar($bar)
{
if (!$this->bars->contain($bar)) {
$this->bars[] = $bar;
$bar->setFoo($this);
}
}
}
class Bar
{
/** @OneToMany(targetEntity="Foo",inversedBy="bars") */
private $foo;
public function setFoo($foo)
{
if ($this->foo !== $foo) {
$this->foo = $foo;
$foo->addBar($this);
}
}
}