generate from create symfony orm doctrine2 entitymanager

symfony - from - EntityManager está cerrado



symfony 4 create entity from database (11)

[Doctrine/ORM/ORMException] The EntityManager is closed.

Después de obtener una excepción DBAL al insertar datos, EntityManager se cierra y no puedo volver a conectarlo.

Intenté así, pero no obtuvo una conexión.

$this->em->close(); $this->set(''doctrine.orm.entity_manager'', null); $this->set(''doctrine.orm.default_entity_manager'', null); $this->get(''doctrine'')->resetEntityManager(); $this->em = $this->get(''doctrine'')->getEntityManager();

Alguien una idea de cómo volver a conectar?


Así es como resolví Doctrine "El EntityManager está cerrado". problema. Básicamente cada vez que hay una excepción (es decir, una clave duplicada) Doctrine cierra el administrador de la entidad. Si aún desea interactuar con la base de datos, debe reiniciar el resetManager() Entidades llamando al método resetManager() mencionado por JGrinon .

En mi aplicación, estaba ejecutando varios consumidores de RabbitMQ que hacían lo mismo: comprobar si una entidad estaba allí en la base de datos, si la devolvía, si no, crearla y luego devolverla. En los pocos milisegundos entre verificar si esa entidad ya existía y crearla, otro consumidor hizo lo mismo y creó la entidad que falta, haciendo que el otro consumidor incurra en una excepción de clave duplicada.

Esto condujo a un problema de diseño de software. Básicamente, lo que estaba tratando de hacer era crear todas las entidades en una transacción. Esto puede parecer natural para la mayoría pero definitivamente fue un error conceptual en mi caso. Considere el siguiente problema: tuve que almacenar una entidad de Partido de fútbol que tenía estas dependencias.

  • un grupo (es decir, Grupo A, Grupo B ...)
  • una ronda (es decir, semifinales)
  • un lugar (es decir, estadio donde se lleva a cabo el partido)
  • un estado de coincidencia (es decir, medio tiempo, tiempo completo)
  • los dos equipos jugando el partido
  • el partido en sí

Ahora, ¿por qué la creación del lugar debería estar en la misma transacción que el partido? Podría ser que acabo de recibir un nuevo lugar que no está en mi base de datos, así que primero tengo que crearlo. Pero también podría ser que ese lugar pueda albergar otro partido, por lo que otro consumidor probablemente intente crearlo también al mismo tiempo. Entonces, lo que tenía que hacer era crear todas las dependencias primero en transacciones separadas, asegurándome de que estaba restableciendo el administrador de entidades en una excepción de clave duplicada. Diría que todas las entidades que se encuentran al lado del partido podrían definirse como "compartidas" porque podrían ser parte de otras transacciones en otros consumidores. Algo que no es "compartido" allí es el mismo partido que probablemente no será creado por dos consumidores al mismo tiempo. Así que en la última transacción espero ver solo el partido y la relación entre los dos equipos y el partido. Todo esto también condujo a otro problema. Si restablece el Administrador de Entidades, todos los objetos que haya recuperado antes de restablecer son totalmente nuevos para Doctrine. ¡Entonces Doctrine no intentará ejecutar una ACTUALIZACIÓN en ellos sino un INSERTO ! Así que asegúrese de crear todas sus dependencias en transacciones lógicamente correctas y luego recuperar todos sus objetos desde la base de datos antes de configurarlos para la entidad objetivo. Considere el siguiente código como un ejemplo:

$group = $this->createGroupIfDoesNotExist($groupData); $match->setGroup($group); // this is NOT OK! $venue = $this->createVenueIfDoesNotExist($venueData); $round = $this->createRoundIfDoesNotExist($roundData); /** * If the venue creation generates a duplicate key exception * we are forced to reset the entity manager in order to proceed * with the round creation and so we''ll loose the group reference. * Meaning that Doctrine will try to persist the group as new even * if it''s already there in the database. */

Así que así es como creo que debería hacerse.

$group = $this->createGroupIfDoesNotExist($groupData); // first transaction, reset if duplicated $venue = $this->createVenueIfDoesNotExist($venueData); // second transaction, reset if duplicated $round = $this->createRoundIfDoesNotExist($roundData); // third transaction, reset if duplicated // we fetch all the entities back directly from the database $group = $this->getGroup($groupData); $venue = $this->getVenue($venueData); $round = $this->getGroup($roundData); // we finally set them now that no exceptions are going to happen $match->setGroup($group); $match->setVenue($venue); $match->setRound($round); // match and teams relation... $matchTeamHome = new MatchTeam(); $matchTeamHome->setMatch($match); $matchTeamHome->setTeam($teamHome); $matchTeamAway = new MatchTeam(); $matchTeamAway->setMatch($match); $matchTeamAway->setTeam($teamAway); $match->addMatchTeam($matchTeamHome); $match->addMatchTeam($matchTeamAway); // last transaction! $em->persist($match); $em->persist($matchTeamHome); $em->persist($matchTeamAway); $em->flush();

Espero que ayude :)


En el controlador.

La excepción cierra el administrador de la entidad. Esto crea problemas para la inserción masiva. Para continuar, necesita redefinirlo.

/** * @var /Doctrine/ORM/EntityManager */ $em = $this->getDoctrine()->getManager(); foreach($to_insert AS $data) { if(!$em->isOpen()) { $this->getDoctrine()->resetManager(); $em = $this->getDoctrine()->getManager(); } $entity = new /Entity(); $entity->setUniqueNumber($data[''number'']); $em->persist($entity); try { $em->flush(); $counter++; } catch(/Doctrine/DBAL/DBALException $e) { if($e->getPrevious()->getCode() != ''23000'') { /** * if its not the error code for a duplicate key * value then rethrow the exception */ throw $e; } else { $duplication++; } } }


Este es un problema muy complicado ya que, al menos para Symfony 2.0 y Doctrine 2.1, no es posible de ninguna manera reabrir el EntityManager después de que se cierra.

La única forma que he encontrado para superar este problema es crear tu propia clase de conexión DBAL, ajustar Doctrine y proporcionar manejo de excepciones (por ejemplo, volver a intentar varias veces antes de mostrar la excepción al EntityManager). Es un poco hacky y me temo que puede causar cierta inconsistencia en los entornos transaccionales (es decir, no estoy realmente seguro de lo que sucederá si la consulta que falla está en el medio de una transacción).

Una configuración de ejemplo a seguir por este camino es:

doctrine: dbal: default_connection: default connections: default: driver: %database_driver% host: %database_host% user: %database_user% password: %database_password% charset: %database_charset% wrapper_class: Your/DBAL/ReopeningConnectionWrapper

La clase debería comenzar más o menos así:

namespace Your/DBAL; class ReopeningConnectionWrapper extends Doctrine/DBAL/Connection { // ... }

Una cosa muy molesta es que debe anular cada método de conexión que proporciona su envoltorio de manejo de excepciones. Usar cierres puede aliviar algo de dolor allí.


Este es un problema muy viejo, pero tuve un problema similar. Estaba haciendo algo como esto:

// entity $entityOne = $this->em->find(Parent::class, 1); // do something on other entites (SomeEntityClass) $this->em->persist($entity); $this->em->flush(); $this->em->clear(); // and at end I was trying to save changes to first one by $this->em->persist($entityOne); $this->em->flush(); $this->em->clear();

El problema fue que despejaron todas las entidades, incluido el primero y arrojaron un error. El EntityManager está cerrado.

En mi caso, la solución consistía en hacer claro en un tipo distinto de Entidad y dejar $entityOne aún bajo EM:

$this->em->clear(SomeEntityClass::class);


Intenta usar:

$em->getConnection()->[setNestTransactionsWithSavepoints][1](true);

antes de comenzar una transacción.

En el método Connection::rollback comprueba la propiedad nestTransactionsWithSavepoints .


Me enfrenté al mismo problema. Después de mirar varios lugares aquí, es cómo lo resolví.

//function in some model/utility function someFunction($em){ try{ //code which may throw exception and lead to closing of entity manager } catch(Exception $e){ //handle exception return false; } return true; } //in controller assuming entity manager is in $this->em $result = someFunction($this->em); if(!$result){ $this->getDoctrine()->resetEntityManager(); $this->em = $this->getDoctrine()->getManager(); }

¡Espero que esto ayude a alguien!


Mi solución.

Antes de hacer nada, compruebe:

if (!$this->entityManager->isOpen()) { $this->entityManager = $this->entityManager->create( $this->entityManager->getConnection(), $this->entityManager->getConfiguration() ); }

Todas las entidades serán guardadas. Pero es útil para una clase particular o algunos casos. Si tiene algunos servicios con entitymanager inyectado, aún estará cerrado.


Puede restablecer su EM por lo

// reset the EM and all aias $container = $this->container; $container->set(''doctrine.orm.entity_manager'', null); $container->set(''doctrine.orm.default_entity_manager'', null); // get a fresh EM $em = $this->getDoctrine()->getManager();


Tuve este problema Así como lo arreglé

La conexión parece cerrarse al intentar vaciar o persistir. Intentar volver a abrirlo es una mala elección porque crea problemas nuevos. Intenté entender por qué se cerró la conexión y descubrí que estaba haciendo demasiadas modificaciones antes de que persistiera.

persist () anteriormente resolvió el problema.


Symfony 2.0 :

$em = $this->getDoctrine()->resetEntityManager();

Symfony 2.1+ :

$em = $this->getDoctrine()->resetManager();


// first need to reset current manager $em->resetManager(); // and then get new $em = $this->getContainer()->get("doctrine"); // or in this way, depending of your environment: $em = $this->getDoctrine();