Doctrine 2 многоуровневый каскад OneToOne - PullRequest
6 голосов
/ 02 февраля 2012

У меня есть три объекта Doctrine: Устройство, которое имеет отношение OneToOne с Device \ Status, которое, в свою очередь, имеет отношение OneToOne с Device \ Status \ Battery.

Я установил {cascade = "persist"} между связанными сущностями, и из того, что я прочитал, это должно быть все, что требуется для Doctrine, чтобы автоматически сохранять каждую из сущностей, не делая ничего самостоятельно в код.

Вот с чем у меня проблемы:

$device = new \Entities\Device();
$device->setId(100);

$status = $device->getStatus();
$status->setIpAddress('192.168.0.1');

$battery = $status->getBattery();
$battery->setInternalLevel(60);

$em->persist($device);
$em->flush();

После выполнения этого кода я получаю следующую ошибку:

Entity of type Device\Status\Battery has identity through a foreign entity 
Device\Status, however this entity has no identity itself. You have to call 
EntityManager#persist() on the related entity and make sure that an identifier 
was generated before trying to persist 'Device\Status\Battery'. In case of 
Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) 
this means you have to call EntityManager#flush() between both persist 
operations.

Мой вопрос: как правильно настроить мои сущности, чтобы они сохранялись в правильном порядке?

Код для сущностей можно найти здесь: https://gist.github.com/1753524

Все тесты были выполнены с использованием песочницы Doctrine 2.2.

Ответы [ 2 ]

6 голосов
/ 07 февраля 2012

Я думаю, что @CappY прав.

Проблема в объекте Status.когда вы делаете getBattery() и создаете новый экземпляр Battery, он связан с экземпляром Status, для которого вы вызвали getBattery().

Поскольку этот экземпляр еще не сохранен в базе данных, его идентификатор hasn 't был сгенерирован (потому что он аннотирован как @GeneratedValue).ты почти прав насчет каскадного сохранениякроме этого он выполняется в памяти .

Таким образом, необходимо , чтобы сохранить и очистить сущность Status перед выполнением getBattery(), если вы хотите использовать эту сущность в качестве идентификатора в Battery.Или же вы можете просто добавить поле идентификатора для батареи :)

0 голосов
/ 01 марта 2013

Вы должны добавить cascade = {"persist"} к вашему отображению отношений. Ответ, выбранный вами как правильный, также является правильным, но с этим решением, если что-то пойдет не так после вставки родительских данных, отката транзакции не будет. Вы должны установить autocommit = false и выполнить транзакцию вручную. С cascade = {"persist"} вам не нужно. Что-то пойдет не так во время действия базы данных, все будет отменено.

...