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

发布于 2024-11-24 04:19:03 字数 1097 浏览 4 评论 0原文

我在确保对象之间的关系保持一致时遇到问题。我正在使用 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::addBarBar::setFoo 时,它将陷入无限循环。那么,应该如何实现 FooBar 才能按设计工作?

Doctrine 2“入门”指南中的用户/错误示例只是通过仅确保 addBar 中的一致性而不是 setFoo 中的一致性来绕过该问题。

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

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

I am having a problem ensuring that relations between my objects remain consistent. I am using Doctrine 2, but this probably applies to other languages and ORM mappers as well.

Doctrine says that relationships have an owning side and an inverse side. If you use bidirectional relationships, then you need to ensure consistency yourself. Basically than means, when one side of the relationship changes, you manually need to update the other side.

Here my example where 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);
    }
}

Now obviously, the code above will not work as intended. When Foo::addBar or Bar::setFoo is called it will descend into an infinite loop. So, how should Foo and Bar be implemented so this works as designed?

The User/Bug example in the Doctrine 2 "Getting started" guide simply skirts around the issue by only ensuring consistency in addBar and not in setFoo.

The wall that I am running into is that is that both addBar and setFoo must be public functions or I cannot call them from the related model. But that means that developers using these objects could use either function to create new relationships.

How do I solve this? How do other languages and mappers solve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

枯叶蝶 2024-12-01 04:19:03

我不知道其他映射器或此类如何解决这个问题,但基本上在 Doctrine 2 中...

当他们在手册中谈论“拥有方”时,他们指的是您的代码应始终使用的实体来将对象与之关联。

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

所以拥有实体应该做的是确保关系的一致性。 “非拥有”方应该只设置关联属性。

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

I don't know how other mappers or such solve this, but basically in Doctrine 2...

When they talk about the "owning side" in the manual, they refer to the entity which your code should always use to associate the objects with.

This is mostly a semantic decision: For example, if you have cars and tires, it makes sense that a tire is added to a car $car->addTire($tire); and the car is not added to the tire $tire->setCar($car);

So what the owning entity should do is ensure the consistency of the relation. The "non-owning" side should just set the association property.

So yeah, if your code incorrectly uses the non-owning side, the relation may end up inconsistent. However, this is only a problem during the execution of the script. Even if you don't set up the relation in both ends, it will get stored correctly in the DB, so the next time the data is fetched, it will get set up between the entities in a consistent manner.

埖埖迣鎅 2024-12-01 04:19:03

到目前为止,这是我的方法。只是添加了一些检查。

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

This is my approach so far. Just added some checks.

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);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文