2012-02-02 22 views
6

Tengo tres entidades Doctrine: Dispositivo, que tiene una relación OneToOne con Device \ Status, que a su vez tiene una relación OneToOne con Device \ Status \ Battery.Doctrine 2 multinivel OneToOne Cascade

Tengo {cascade = "persist"} establecido entre las entidades relacionadas, y por lo que he leído, debería ser todo lo que se requiere para que Doctrine persista automáticamente en cada una de las entidades sin tener que hacer nada yo mismo en el código.

Aquí es lo que estoy teniendo problemas con:

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

Después de ejecutar este código, me sale el siguiente 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. 

Mi pregunta es: ¿cuál es la forma correcta de configurar mi entidades para asegurarse de que persistan en el orden correcto?

El código para las entidades se puede encontrar aquí: https://gist.github.com/1753524

Todas las pruebas se han realizado utilizando la caja de arena Doctrina 2.2.

+0

Tuve casi el mismo problema. Tienes que llamar a color entre cada persistencia. – CappY

+0

@CappY Según los documentos de Doctrine, dado que tengo {cascade = "persist"} establecido para cada entidad, no es necesario que persista manualmente cada entidad. Este código * debería * funcionar como está. http://readthedocs.org/docs/doctrine-orm/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations – Taeram

+0

Proporcione un [ejemplo corto, autónomo, correcto] (http : //sscce.org/). Su código desencadena una violación de acceso al intentar asignar valores directamente a las propiedades 'protected', es decir,' $ device-> id = 100' – Phil

Respuesta

6

Creo que @CappY tiene razón.

El problema está en la entidad de estado. cuando hace getBattery() y crea una nueva instancia de batería, está relacionada con la instancia de estado en la que llamó al getBattery().

Dado que esa instancia no se ha almacenado aún en la base de datos, su ID no se ha generado (porque está anotado como @GeneratedValue). tienes casi razón sobre la persistencia de la cascada. a excepción de que se realiza en la memoria.

Así que necesita para persistir y purgar Entidad de estado antes de hacer getBattery() si desea utilizar esa entidad como id en la batería. O bien, simplemente podría agregar un campo de identificación para Batería :)

+0

Me acabo de dar cuenta de que en realidad tuve que presionar el botón "+50" para otorgar la recompensa, y no solo aceptar su respuesta. Así que ahí tienes :) – Taeram

+0

muchas gracias :) – jere

0

Tiene que agregar cascade = {"persist"} a su relación de asignación. La respuesta que seleccionó como correcta también es correcta, pero con esa solución, si algo sale mal después de que se inserten los datos principales, no habrá ninguna reversión de transacción. Debe establecer autocommit = false y realizar la transacción de confirmación manualmente. Con cascade = {"persist"} no es necesario. Todo va mal durante la acción de la base de datos, todo se revertirá.

+0

Eso es lo que estaba haciendo y no funcionó. ¿Puedes proporcionar un ejemplo completo de trabajo? – cheesemacfly