Doctrine 2多级OneToOne Cascade

时间:2012-02-02 17:46:41

标签: php orm doctrine mapping doctrine-orm

我有三个Doctrine实体:Device,它与Device \ Status具有OneToOne关系,后者与Device \ Status \ Battery具有OneToOne关系。

我在相关实体之间设置了{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 个答案:

答案 0 :(得分:6)

我认为@CappY是对的。

问题出在Status实体中。当您执行getBattery()并创建新的Battery实例时,它与您调用getBattery()的状态实例相关。

由于该实例尚未存储在数据库中,因此尚未生成其id(因为它的注释为@GeneratedValue)。你对瀑布持续存在几乎是正确的。除了它在内存中执行

因此,如果您想要将该实体用作Battery中的ID,那么需要在执行getBattery()之前保持并刷新状态实体。或者你可以简单地为Battery添加一个id字段:)

答案 1 :(得分:0)

您必须在关系映射中添加cascade = {" persist"}。您选择的答案也是正确的但是使用该解决方案,如果在插入父数据后出现任何问题,则不会发生事务回滚。您必须设置autocommit = false并手动执行提交事务。使用cascade = {" persist"}你不必。在数据库操作期间出现任何问题,所有内容都将被回滚。