2012-09-05 12 views
9

Entonces, después de una violación a la restricción de integridad con Doctrine2, al EntityManager le gusta cerrar de una manera que hace imposible continuar usando dicho EntityManager. El pensamiento predominante parece ser que debe crear un nuevo EntityManager en lugar de permitirle atrapar esta simple excepción y manejarla de manera elegante (diseño maravilloso, chicos/sarcasmo).Tratar con un EntityManager cerrado con Bisna/Doctrine2

Sin embargo, surge un problema cuando se usa la librería Bisna/ZF 1.12 con un administrador de entidad cerrado. La biblioteca de Bisna no proporciona un método público para crear un nuevo EntityManager con el mismo nombre (es decir, "predeterminado") después de haber sido cerrado en la clase Container.

Mi pregunta es cuál es la mejor manera de tratar este problema. Simplemente tiene que haber una forma de recuperarse con gracia después de una violación de restricción de integridad.

+0

utilizando el registro doctrina podría restablecer un gestor de entidad cerrada. – Florian

+0

ver https://github.com/symfony/symfony/issues/5339 – Florian

Respuesta

2

En lugar de tratar de recuperarse de estas situaciones, usted debe centrarse en la prevención de integridad violaciónes restricción:

  • Si llega a una restricción de clave externa, no está atando las entidades juntos en la derecha manera.
  • Si tocas una restricción única, debes verificar el db para ver si hay datos duplicados antes de tratar de persistir.
  • Si usted choca con otro tipo de restricción y no sabe cómo prevenirlo, por favor pregunte :)

ACTUALIZACIÓN:

La razón Doctrine2 cierra el EntityManager es porque en la mayoría de los casos es ya no es seguro de usar. Su UnitOfWork contiene operaciones que no se pueden hacer (de ahí la excepción que se lanza).

Tiene razón en que la biblioteca de Bisna no es compatible con la creación de un nuevo EntityManager. Puede ampliarlo para implementar dicha funcionalidad usted mismo.

Otra solución sería handle transactions manually:

$em->getConnection()->beginTransaction(); // suspend auto-commit 
try { 
    // do some work 
    $user = new User; 
    $user->setName('George'); 
    $em->persist($user); 
    $em->flush(); 
    $em->getConnection()->commit(); 
} catch (Exception $e) { 
    $em->getConnection()->rollback(); 
    $em->clear(); // in stead of $em->close(); 
    throw $e; 
} 

Al reemplazar $em->close() con $em->clear() se mantiene el EntityManager abierta y limpia a utilizar de nuevo.

I le animo a cualquieracerca o clara EntityManager, ya que los datos en él es (casi siempre) ya no es utilizable.

+1

Hay situaciones en las que simplemente no puede saber de antemano. Un ejemplo simple son los clientes múltiples conectados a la base de datos, que obviamente es común. Pueden insertar datos duplicados inmediatamente después de que el cheque esté en su lugar, pero antes de que su cliente los guarde. Simplemente no puede evitar esto, solo mediante el uso de bloqueos de base de datos de tipo exclusivo (y realmente no los queremos). Entonces, recuperarse de este tipo de error es bastante esencial. –

+0

Acepto que debe recuperarse en este caso particular, pero probablemente no necesite un nuevo EntityManager en la misma solicitud (porque el usuario/cliente necesita volver a evaluar su entrada). PD: Doctrine proporciona bloqueo, consulte http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#version y http://docs.doctrine-project.org /es/2.0.x/reference/transactions-and-concurrency.html#locking-support –

0

Manipular las transacciones manualmente no parece ser el truco para mí. Doctrine aún cerró el administrador de la entidad incluso si solo usé el método claro. Bifuré a Bisna e hice algunas modificaciones a la clase Container, agregando un método "resetEntityManager", que parece funcionar bien.

Así que ahora mi código es el siguiente:

try { 
    $user = new User; 
    $user->setName('George'); 
    $em->persist($user); 
    $em->flush(); 
} catch (Exception $e) { 
    $dc = \Zend_Registry::get('doctrine'); //returns Bisna\Doctrine\Container 
    $em = $dc->resetEntityManager(); //returns the new instance 
    throw $e; 
} 

clase Container revisado está aquí:

https://github.com/ajlozier/zendframework1-doctrine2/blob/ea46703e909149cba43edca56c91d5de2ab7a7f9/library/Bisna/Doctrine/Container.php