Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine entitymanager clear doesn't fully clear

I have this piece of code:

$entityManager->clear('Reza\MyBundle\Entity\ListItem');

$identity = $entityManager->getUnitOfWork()->getIdentityMap();
foreach ($identity as $class => $objectlist) {
    if ($class == 'Reza\MyBundle\Entity\ListItem') {
        print "didn't fully clear, exiting..\n ";
        exit;
    }
}

You would think that after I pass in the classname to clear, you should not see those objects in the unit of work anymore, but by looking at the source I noticed that when you pass an argument to the clear() function it only detaches entities of that type. On the other hand, if I don't pass any arguments to clear() it detaches and does in fact clear, so the above code does not hit line 138, exit. So that means it not only detaches all entities, but also clears the unit of work.

Anyone has any thoughts on this? Should I file a bug with doctrine?

like image 609
Reza S Avatar asked Sep 28 '13 00:09

Reza S


People also ask

What is persist flush?

Persist and flush​ flush() . em. persist(entity, flush?: boolean) is used to mark new entities for future persisting. It will make the entity managed by given EntityManager and once flush will be called, it will be written to the database.

How Doctrine works?

Doctrine uses the Identity Map pattern to track objects. Whenever you fetch an object from the database, Doctrine will keep a reference to this object inside its UnitOfWork. The array holding all the entity references is two-levels deep and has the keys root entity name and id.

What is entity manager in Doctrine?

The EntityManager is the central access point to ORM functionality. It can be used to find, persist, flush and remove entities.

Why is EntityManager closed?

Having a failure at DB level during the transaction (in your try { }) will cause the EntityManager to be closed.


1 Answers

I would say that technically it is not a bug as clear() works as described in the documentation, see Doctrine2 API, documentation and source code (current version).

The clear() method is just a way to detach() all entities or entities of a specified type. It can be thought as a "Multi-Detach", its purpose does not extend past detaching.

When detaching all entities using clear() Doctrine detaches the entities using the most efficient method possible. In the process the Identity Map Array is set to an empty array(). This will give the appearance of what I believe you are referring to as cleared.

$entityManager->clear();
$identity = $entityManager->getUnitOfWork()->getIdentityMap(); 
//This will return a an empty array() to $identity
//therefore $identity['Reza\MyBundle\Entity\ListItem'] would be undefined

If we assume that data was retrieved for an entity of Reza\MyBundle\Entity\ListItem. Then in the following example we can see that the unit of work has at least 1 Reza\MyBundle\Entity\ListItem object.

$identity = $entityManager->getUnitOfWork()->getIdentityMap();
$count = count($identity['Reza\MyBundle\Entity\ListItem']);
// $count would be > 0;

However, when you use clear($entityName) and clear by entity type, the cleared/detached entities are removed from the unit of work, it is only the array key [$entityName] that remains, not any of the objects.

$entityManager->clear('Reza\MyBundle\Entity\ListItem');
$identity = $entityManager->getUnitOfWork()->getIdentityMap(); 
$count = count($identity['Reza\MyBundle\Entity\ListItem']);
//$count would be == 0. All Objects cleared/detached.

This functionality is all that is specified by the documentation.

I do think a feature request is in order, to make it work more consistently. When invoking clear($entityName) Doctrine should unset() the remaining key thereby making it undefined (cleared). This would allow us to more easily write code that would work whether we used clear() or clear($entityName).

like image 132
hcoat Avatar answered Sep 20 '22 02:09

hcoat