确保对象关系的一致性(原则2)


Ensuring object relationship consistency (doctrine 2)

我在确保对象之间的关系保持一致时遇到了问题。我正在使用原则2,但这可能也适用于其他语言和ORM映射器。

原则说关系有拥有的一面和相反的一面。如果你使用双向关系,那么你需要确保自己的一致性。基本上,than的意思是,当关系的一方发生变化时,您需要手动更新另一方。

这里是我的例子,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::addBarBar::setFoo时,它将下降到一个无限循环。那么,应该如何实现 FooBar以使其按设计工作?

原则2 "入门"指南中的用户/Bug示例只是通过确保addBar的一致性而不是setFoo来绕过这个问题。

我遇到的墙是,addBarsetFoo必须是公共函数,否则我不能从相关模型调用它们。但这意味着使用这些对象的开发人员可以使用任意一个函数来创建新的关系。

如何解决这个问题?其他语言和映射器如何解决这个问题?

我不知道其他映射器是如何解决这个问题的,但基本上在Doctrine 2中…

当他们在手册中谈到"拥有方"时,他们指的是你的代码应该总是用来关联对象的实体。

这主要是一个语义决策:例如,如果您有汽车和轮胎,将轮胎添加到汽车$car->addTire($tire);而不将汽车添加到轮胎$tire->setCar($car);是有意义的

所以拥有实体应该做的是保证关系的一致性。"非拥有"端应该只设置关联属性。

所以,是的,如果你的代码不正确地使用了非拥有的一方,关系可能会不一致。然而,这只是在脚本执行期间的问题。即使您没有在两端设置关系,它也会正确地存储在DB中,因此下次获取数据时,它将以一致的方式在实体之间设置。

这是我目前的方法。只是增加了一些检查。

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);
        }
    }
}