Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine 2 multi-level OneToOne Cascade

I have three Doctrine entities: Device, which has a OneToOne relationship with Device\Status, which in turn has a OneToOne relationship with Device\Status\Battery.

I have {cascade="persist"} set between the related entities, and from what I've read, that should be all that is required for Doctrine to automatically persist each of the entities without having to do anything myself in the code.

Here's what I'm having problems with:

$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();

After executing this code, I get the following error:

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.

My question is: what is the correct way to setup my entities to ensure that they're persisted in the correct order?

The code for the entities can be found here: https://gist.github.com/1753524

All tests have been performed using the Doctrine 2.2 sandbox.

like image 794
Taeram Avatar asked Feb 02 '12 17:02

Taeram


1 Answers

I think @CappY is right.

The problem is in the Status entity. when you do getBattery() and create a new Battery instance, it's related to the Status instance on which you called getBattery().

Since that instance hasn't been stored in the database yet, it's id hasn't been generated (because it's annotated as @GeneratedValue). you're almost right about cascade persist. except for that it's performed in memory.

So you need to persist and flush Status entity before doing getBattery() if you want to use that entity as id in Battery. Or else you could simple add an id field for Battery :)

like image 102
jere Avatar answered Oct 16 '22 22:10

jere