Обеспечение согласованности объектных отношений (доктрина 2) - PullRequest
1 голос
/ 13 июля 2011

У меня проблема с обеспечением того, чтобы отношения между моими объектами оставались согласованными.Я использую Doctrine 2, но, вероятно, это применимо и к другим языкам и средствам отображения ORM.

Doctrine говорит, что отношения имеют собственную сторону и обратную сторону.Если вы используете двунаправленные отношения, то вам необходимо обеспечить последовательность самостоятельно.По сути, это означает, что когда одна сторона отношения изменяется, вам нужно вручную обновить другую сторону.

Вот мой пример, где 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 должны быть публичными функциями.или я не могу позвонить им из родственной модели.Но это означает, что разработчики, использующие эти объекты, могут использовать любую функцию для создания новых отношений.

Как мне решить эту проблему?Как это решают другие языки и картостроители?

Ответы [ 2 ]

2 голосов
/ 14 июля 2011

Это мой подход до сих пор. Просто добавил несколько проверок.

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);
        }
    }
}
2 голосов
/ 13 июля 2011

Я не знаю, как это решают другие картостроители, но в основном в Doctrine 2 ...

Когда они говорят о «стороне-владельце» в руководстве, они ссылаются на сущность, которую ваш код всегда должен использовать для связи объектов.

Это в основном семантическое решение: например, если у вас есть автомобили и шины, имеет смысл добавить шину к автомобилю $car->addTire($tire);, а автомобиль не добавляется к шине $tire->setCar($car);

Итак, что должен сделать объект-владелец, это обеспечить согласованность отношений. Сторона, не являющаяся владельцем, должна просто установить свойство ассоциации.

Так что, да, если ваш код неправильно использует несобственную сторону, отношение может оказаться несовместимым. Однако это только проблема во время выполнения скрипта. Даже если вы не настроите отношение в обоих концах, оно будет правильно сохранено в БД, поэтому при следующем получении данных оно будет настроено между объектами согласованным образом.

...