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);
So, as I think, this should be done.
$group = $this->createGroupIfDoesNotExist($groupData);
I hope this helps :)