EntityManager is closed

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

After receiving a DBAL exception when inserting data, the EntityManager closes and I cannot reconnect it.

I tried so, but did not get a connection.

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

Does anyone know how to connect?

+72
orm symfony entitymanager doctrine2 doctrine-orm
Jan 10 '13 at
source share
16 answers

This is a very difficult problem because, at least for Symfony 2.0 and Doctrine 2.1, it is not possible to re-open the EntityManager in any way after it is closed.

The only way I decided to overcome this problem is to create my own DBAL join class, wrap Doctrine and provide exception handling (for example, repeat several times before throwing an exception from EntityManager). This is a bit of a hack, and I'm afraid that this might cause some inconsistency in transactional environments (i.e. I'm not quite sure what will happen if the request fails in the middle of the transaction).

An example of such a configuration:

 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 

A class should begin more or less as follows:

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

It is very unpleasant that you need to override each Connection method that provides your exception handling shell. Using closures can ease the pain there.

+23
Jan 10 '13 at 15:23
source share

My decision.

Before doing anything, check:

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

All objects will be saved. But it is convenient for a certain class or some cases. If you have some services with an injected noun, it will still be closed.

+59
Sep 29 '13 at 10:36 on
source share

Symfony 2.0 :

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

Symfony 2.1 + :

 $em = $this->getDoctrine()->resetManager(); 
+34
Feb 13 '14 at 10:29
source share

That is how I decided the Doctrine of "EntityManager is closed." . Usually every time an exception occurs (i.e. a duplicate key), Doctrine closes the Entity Manager. If you still want to interact with the database, you need to reset the Entity Manger by calling the resetManager() method, as JGrinon mentioned.

In my application, I launched several RabbitMQ consumers, who all did the same thing: checked if the object was in the database, if so, returned it, if it had not been created, and then returned. Within a few milliseconds between checking whether this entity already exists and creating it, another consumer did the same and created the missing entity, due to which the other consumer encountered an exception due to a duplicate key ( race condition ).

This led to a software design problem. Essentially, I tried to create all the objects in one transaction. For most, this may seem natural, but in my case it was definitely conceptually wrong. Consider the following problem: I needed to store a football match facility that had these dependencies.

  • group (e.g. group A, group B ...)
  • round (e.g. semifinal ...)
  • venue (i.e. the stadium where the match is taking place)
  • match status (e.g. half time, full time)
  • two teams play a match
  • match itself

Now, why does the creation of a place have to be in the same transaction as the match? Maybe I just got a new place that is not in my database, so I need to create it first. But it can also happen that another match can be played at that place, so that another consumer is likely to try to create it at the same time. Therefore, I had to first create all the dependencies in individual transactions, making sure that I reset the entity manager to exclude the duplicate key. I would say that all entities that are close to the match can be defined as “general” because they can potentially be part of other transactions of other consumers. Something that is not “divided” there is a coincidence itself, which is unlikely to be created by two consumers at the same time. So in the last transaction, I expect to see only the match and the relationship between the two teams and the match.

All this also led to another problem. If you reset Entity Manager, all objects that you retrieved before the reset are completely new to Doctrine. Therefore, Doctrine will not try to run UPDATE for them other than INSERT! Therefore, make sure that you create all of your dependencies in logically correct transactions, and then retrieve all of your objects back from the database before setting them for the target. Consider the following code as an example:

 $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 already there in the database. */ 

So, as I think, this should be done.

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

I hope this helps :)

+19
Jun 29 '15 at 10:00
source share

You can reset your em, therefore

 // 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(); 
+17
May 16 '13 at 19:06
source share

In the controller.

Exception closes the entity manager. This creates problems for bulk insertion. To continue, you need to override it.

 /** * @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++; } } } 
+3
Jul 16 '15 at 11:37
source share

In Symfony 4. 2+, you should use the package:

 composer require symfony/proxy-manager-bridge 

otherwise, you will get an exception:

 Resetting a non-lazy manager service is not supported. Declare the "doctrine.orm.default_entity_manager" service as lazy. 

Then you can reset the entityManager as follows:

services.yaml:

 App\Foo: - '@doctrine.orm.entity_manager' - '@doctrine' 

foo.php:

 use Doctrine\Bundle\DoctrineBundle\Registry; use Doctrine\DBAL\DBALException; use Doctrine\ORM\EntityManagerInterface; try { $this->entityManager->persist($entity); $this->entityManager->flush(); } catch (DBALException $e) { if (!$this->entityManager->isOpen()) { $this->entityManager = $this->doctrine->resetManager(); } } 
+3
Jun 17 '19 at 12:36
source share

As far as I know, this problem occurred in the batch import command due to the fact that the try / catch loop detects an SQL error (using em->flush() ), which I did not do anything about. In my case, this was because I was trying to insert a record with a non-nullable property left as null.

This can usually lead to a critical exception, and the command or controller should stop, but I just logged this problem and continue. An SQL error caused the object manager to close.

Check the dev.log file for any dumb SQL errors like this, as that might be your mistake. :)

+1
Sep 04 '18 at 10:23
source share

Try using:

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

before starting a transaction.

In Connection::rollback mode, it checks the nestTransactionsWithSavepoints property.

0
Oct 24 '13 at 18:53 on
source share

I had this problem. This is how I fixed it.

The connection seems to close when trying to reset or save. Trying to renew it is a bad choice because it creates new problems. I tried to understand why the connection was closed, and found that I was making too many changes before it continued.

persist () previously solved the problem.

0
Feb 13 '15 at 12:58
source share

This is a really old problem, but I had a similar problem. I was doing something like this:

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

The problem was that it cleared all objects, including the first one, and threw the EntityManager closed error .

In my case, the solution was simply to clarify a separate Entity type and leave $entityOne still in EM:

 $this->em->clear(SomeEntityClass::class); 
0
Mar 02 '16 at 15:48
source share

Symfony v4.1.6

Doctrine v2.9.0

The process of inserting duplicates into the repository

  1. Get registry access in your repo



 //begin of repo /** @var RegistryInterface */ protected $registry; public function __construct(RegistryInterface $registry) { $this->registry = $registry; parent::__construct($registry, YourEntity::class); } 

  1. Wrap a risky code in a transaction and a rested manager in case of an exception



 //in repo method $em = $this->getEntityManager(); $em->beginTransaction(); try { $em->persist($yourEntityThatCanBeDuplicate); $em->flush(); $em->commit(); } catch (\Throwable $e) { //Rollback all nested transactions while ($em->getConnection()->getTransactionNestingLevel() > 0) { $em->rollback(); } //Reset the default em if (!$em->isOpen()) { $this->registry->resetManager(); } } 

0
Dec 6 '18 at 8:51
source share

I found an interesting article about this issue.

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

Doctrine 2 EntityManager exception closed

0
Apr 18 '19 at 15:18
source share

I encountered the same problem when testing changes in Symfony 4.3.2

I lowered the log level to INFO

And ran the test again

And the logged in showed this:

 console.ERROR: Error thrown while running command "doctrine:schema:create". Message: "[Semantical Error] The annotation "@ORM\Id" in property App\Entity\Common::$id was never imported. Did you maybe forget to add a "use" statement for this annotation?" {"exception":"[object] (Doctrine\\Common\\Annotations\\AnnotationException(code: 0): [Semantical Error] The annotation \"@ORM\\Id\" in property App\\Entity\\Common::$id was never imported. Did you maybe forget to add a \"use\" statement for this annotation? at C:\\xampp\\htdocs\\dirty7s\\vendor\\doctrine\\annotations\\lib\\Doctrine\\Common\\Annotations\\AnnotationException.php:54)","command":"doctrine:schema:create","message":"[Semantical Error] The annotation \"@ORM\\Id\" in property App\\Entity\\Common::$id was never imported. Did you maybe forget to add a \"use\" statement for this annotation?"} [] 

This means that some kind of error in the code causes:

 Doctrine\ORM\ORMException: The EntityManager is closed. 

So it’s a good idea to check the magazine.

0
Jul 21 '19 at 9:19
source share
 // 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(); 
-2
Sep 08 '14 at 10:00
source share

I ran into the same problem. Looking at a few places, here's how I dealt with it.

 //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(); } 

Hope this helps someone!

-2
Nov 19 '15 at 13:23
source share



All Articles