Doctrine 2 Tiered OneToOne Cascade

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

I have {cascade = "persist"} installed between related objects and from what I read, this should be all that is required for Doctrine to automatically save each of the entities without having to do anything on its own in the code.

Here I have 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 configure my objects so that they are stored in the correct order?

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

All tests were performed using the Doctrine 2.2 sandbox.

+6
source share
2 answers

I think @CappY is right.

The problem is with the Status object. when you do getBattery() and create a new battery instance, it is associated with the Status instance that you called getBattery() .

Since this instance has not yet been stored in the database, its identifier has not been generated (because it was annotated as @GeneratedValue ). you are almost right about the cascade. except that it was executed in memory.

So you need save and erase the state object before doing getBattery() if you want to use this object as an id in Battery. Or you could just add an id field for the battery :)

+6
source

You must add cascade = {"persist"} to your relationship mapping. The correct answer that you selected is also correct, but with this solution, if something goes wrong after entering the parent data, the transaction will not be rolled back. You must set autocommit = false and execute the commit transaction manually. With cascade = {"persist"} you do not need. Something will go wrong during the database, everything will be canceled.

0
source

Source: https://habr.com/ru/post/907505/


All Articles