Доктрина множественное OneToMany / ManyToOne двунаправленное нарушение ограничения целостности
в последней доктрине о 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
*
* @ORMOneToOne(targetEntity="Address", cascade={"all"}, orphanRemoval=true)
* @ORMJoinColumn(onDelete="cascade")
*/
private $postalAddress;
/**
* @var DoctrineCommonCollectionsCollection otherAddresses
*
* @ORMOneToMany(targetEntity="Address", mappedBy="person", cascade={"all"}, orphanRemoval=true)
*/
private $otherAddresses;
}
class Address
{
/**
* @var Person person
*
* @ORMManyToOne(targetEntity="Person", inversedBy="postalAddress, otherAddresses")
* @ORMJoinColumn(nullable=false)
*/
private $person;
}
Я думал, что это может быть, потому что
inversedBy="postalAddress, otherAddresses"
Я не думаю, что поддерживается несколько inversedBy; затем я также попытался изменить
@ORMJoinColumn(nullable=false)
быть nullable, но я все равно получаю ошибку.
это, очевидно, не тривиальный пример человека/адреса, а что-то более сложное, но это была моя лучшая попытка абстракции.
Я уверен, что пропустил что-то очевидное. Кто-нибудь может помочь?
1 ответов
Сломанное Реляционное Определение
доктрина пытается поддерживать 3 различных отношения:
-
адрес (владеющая сторона) [двунаправленная] $person
--Many:One-->
$otherAddresses человек -
адрес (владеющая сторона) [двунаправленная] $person
--Many:One-->
$postalAddress человек -
человек (владеющая сторона) [однонаправленный] $postalAddress
--One:One-->
$ id адрес
вы видите проблему?
используйте реляционные стандарты для решения этой проблемы.
простое решение здесь использовать очень общую картину дизайна настройка первичного элемента для коллекции. По сути, вам нужно только одно отношение:
-
адрес (владеющая сторона) [двунаправленная] $person
--Many:One-->
$otherAddresses человек
затем добавьте в адрес свойство, которое определяет этот адрес как первичный. Programattically справиться с этим в лицо и адрес лица:
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.
}
использовать два разных отношения, но не пересечь ручьи
если вы сохраняете однонаправленное отношение "один к одному" от человека к адресату, проблема решается сама собой.
-
адрес (владеющая сторона) [двунаправленная] $person
--Many:One-->
$otherAddresses человек -
человек (владеющая сторона) [однонаправленный] $postalAddress
--One:One-->
адрес
у вас все еще будут проблемы здесь хотя, потому что доктрина будет жаловаться, если:
- главная (PostalAddress) адрес не имеет обеих сторон за Много:Один определенными. (таким образом, ваш "основной" адрес также должен быть в $otherAddresses
коллекция).
- попытка удаления или каскадного удаления и обновления приведет к конфликту этих двух отношений, "пересечению потоков" реляционных ограничений доктрины, поэтому вам придется программно обрабатывать эти операции.