[DDC-74] Updates get lost when Lifecycle Events (@PreUpdate) are invoked Created: 29/Oct/09  Updated: 13/Nov/09  Resolved: 13/Nov/09

Status: Closed
Project: Doctrine 2 - ORM
Component/s: Mapping Drivers
Affects Version/s: None
Fix Version/s: 2.0-ALPHA4
Security Level: All

Type: Bug Priority: Critical
Reporter: Nico Kaiser Assignee: Roman S. Borschel
Resolution: Fixed Votes: 1
Labels: None


When Lifecycle Events are invoked on entity update (@PreUpdate), the entity is not updated properly in the database.

This code creates a User object, sets its name to "Bob" and its value to empty, then updates the object and updates the name to "Alice".

$user = new User;

However, when the User class has a @PreUpdate event that e.g. sets the value to "Hello World", the name change gets lost and only the value is updated by the second flush() call.

This is a critical bug which prevents creation of entities that simulate the "Timestampable" behaviour of Doctrine 1.x...

Comment by Benjamin Eberlei [ 02/Nov/09 ]

I think this might be a hen-egg problem.

@PreUpdate is only invoked after it is calculated that a change occured on all those entities that have updates. After a change in @PreUpdate events there would have to be another calculation of changes on all those entities, which would probably mean a significant performance hit.

Comment by Eric Durand-Tremblay [ 13/Nov/09 ]

I may not know all the consequences of this, but I think I have a fix for this bug.

In the class ORM\UnitOfWork

As I understand it, computeSingleEntityChangeSet() is called to update the changeset and _originalEntityData is set to the current values.

But, I see that the old changes are lost.

If i modify the function computeSingleEntityChangeSet to merge the changeset, it works.

At line 656 replace

$this->_entityChangeSets[$oid] = $changeSet;

By :

    $this->_entityChangeSets[$oid] += $changeSet;
else {
    $this->_entityChangeSets[$oid] = $changeSet;

Here is my test case :

$qb = new \Doctrine\ORM\QueryBuilder($em);
			->from('Entity\FNA', 'fna')
			->andwhere($qb->expr()->eq('fna.id', ':fna_id'));
$qb->setParameter('fna_id', 1);
$query = $qb->getQuery();

$fna = $query->getSingleResult();

AND The preUdate :

 * @PreUpdate
public function onPreUpdate($args=false)
        $this->modified_at = new \DateTime();
Comment by Roman S. Borschel [ 13/Nov/09 ]

Indeed this looks like a good fix except that the addition has to be the other way around so that when the same field is changed twice, first before the flush and then in a lifecycle callback/event the change from the callback prevails.

I will work on this and write a test for it.

Thanks Eric.

Comment by Roman S. Borschel [ 13/Nov/09 ]

Fixed now.

Thanks Nico for reporting and thanks Eric for the suggestion!

Generated at Tue Dec 01 02:43:21 EST 2015 using JIRA 6.4.10#64025-sha1:5b8b74079161cd76a20ab66dda52747ee6701bd6.