Доктрина множественное однонаправленное/однонаправленное нарушение ограничения целостности


В последней доктрине о Symfony2 пытается выработать множественную двунаправленную связь между двумя объектами.

Объект владельца человека имеет один почтовый адрес, а затем несколько дополнительных адресов в коллекции, и я удаляю() Человека, я хочу, чтобы все его адреса также были удалены (но удаление адреса не должно удалять человека), но я получаю эту ошибку -

An exception occurred while executing 'DELETE FROM address WHERE id = ?' with
params {"1":"fb5e47de-2651-4069-b85e-8dbcbe8a6c4a"}:

[PDOException] SQLSTATE[23000]: Integrity constraint violation: 1451
Cannot delete or update a parent row: a foreign key constraint fails
(`db`.`address`, CONSTRAINT `FK_633704 C29C1004E`
FOREIGN KEY (`person_id`) REFERENCES `person` (`id`))

В

class Person
{

    /**
     * @var Address postalAddress
     *
     * @ORM\OneToOne(targetEntity="Address", cascade={"all"}, orphanRemoval=true)
     * @ORM\JoinColumn(onDelete="cascade")
     */
    private $postalAddress;

    /**
     * @var \Doctrine\Common\Collections\Collection otherAddresses
     *
     * @ORM\OneToMany(targetEntity="Address", mappedBy="person", cascade={"all"}, orphanRemoval=true)
     */
    private $otherAddresses;


}

class Address
{

    /**
     * @var Person person
     *
     * @ORM\ManyToOne(targetEntity="Person", inversedBy="postalAddress, otherAddresses")
     * @ORM\JoinColumn(nullable=false)
     */
    private $person;
}

Я подумал, что это может быть, потому что

inversedBy="postalAddress, otherAddresses"

Я не думаю, что поддерживается множественное инвертирование; затем я также попытался изменить

@ORM\JoinColumn(nullable=false)

Быть обнуляемым, но я все равно получаю ошибку.

Очевидно, что речь идет не о тривиальном примере человека/адреса, а о чем-то более сложном, но это была моя лучшая попытка абстракции.

Я уверен, что упустил что-то очевидное. Кто-нибудь может помочь?

Author: Gottlieb Notschnabel, 2013-04-24

1 answers

Нарушенное определение отношений

Хотя то, что вы делаете, может иметь смысл с чисто логической точки зрения, это не имеет смысла с точки зрения реляционных данных и, в частности, не имеет смысла с точки зрения Доктрины.

Доктрина пытается поддерживать 3 различных отношения:

  • Адрес (сторона владельца) [двунаправленный] $человек --Many:One--> $Другие адреса Человек
  • Адрес (сторона владельца) [двунаправленный] $персона --Many:One--> $Почтовый адрес Персона
  • Лицо (сторона владельца) [однонаправленный] $Почтовый адрес --One:One--> $идентификатор Адрес

Вы видите проблему?

Используйте реляционные стандарты для решения этой проблемы.

Простое решение здесь состоит в том, чтобы использовать ОЧЕНЬ распространенный шаблон проектирования установки первичного элемента для коллекции. По сути, вам нужна только одна связь:

  • Адрес (сторона владельца) [двунаправленный] $персона --Many:One--> $Другие адреса Персона

Затем добавьте в адрес свойство, которое определяет этот адрес как основной. Программно обработайте это в лицах и адресных сущностях:

Class Person
{
    . . .
    public function getPrimaryAddress() {
        if (null === $this->primaryAddress) {
            foreach($this->getOtherAddresses() as $address) {
                if ($address->isPrimary()) {
                    $this->primaryAddress = $address;
                    break;
                }
            }
        }

        return $this->primaryAddress;
    }

    // similar for the setter, update the old address as not primary if there is one, set the new one as primary.
}

Используйте два разных отношения, но не пересекайте потоки

Если вы сохраняете ОДНОНАПРАВЛЕННЫЕ отношения "Один к одному" от человека к адресату, проблема решается сама собой.

  • Адрес (сторона владельца) [двунаправленный] $человек --Many:One--> $Другие адреса Человек
  • Лицо (сторона владельца) [однонаправленный] $Почтовый адрес --One:One--> Адрес

Однако здесь у вас все равно будут проблемы, потому что Доктрина будет жаловаться, если: - основной (Почтовый адрес ) адрес не имеет обеих сторон для Многих:Один определен. (таким образом, ваш "основной" адрес также должен быть в коллекции $otherAddresses). - попытка удалить или каскадировать удаление и обновление приведут к конфликту этих двух отношений, "пересечению потоков" реляционных ограничений доктрины, поэтому вам придется программно обрабатывать эти операции.

 2
Author: Tony Chiboucas, 2017-10-17 15:14:37