DDC-440: originalEntityData not initialized for proxy loaded via an association using EntityManaget->find() #551

Closed
opened 2026-01-22 12:42:13 +01:00 by admin · 10 comments
Owner

Originally created by @doctrinebot on GitHub (Mar 18, 2010).

Originally assigned to: @beberlei on GitHub.

Jira issue originally created by user rickdt:

Here is the pseudo-code to reproduce.

Let's say we have 2 entity, Person and Phone.
There is a OneToMany relation between Person and Phone.

You get a person entity with the find() method:

$person = $em->find('Person', 1);
$phones = $person->getPhones()
$phone = $phones[0]; // Any would do

$phone->setNumber('999-9999');

$em->persist($phone);
$em->persist($person);
$em->flush();

If you look at the resulting update query, you will see that all fields get updated and not only the "number" field. This is due to the fact that originalEntityData is not loaded and the change set cannot be calculated properly.

I noticed this problem because I need the originalEntityData for an other purpose (creating history records) and it break when I use proxies.

Look at UnitOfWork._createEntity()

if (isset($this->_identityMap[$class->rootEntityName][$idHash])) {
            $entity = $this->_identityMap[$class->rootEntityName][$idHash];
            $oid = spl*object*hash($entity);
            if ($entity instanceof Proxy && ! $entity->*_isInitialized_*) {
                $entity->*_isInitialized_* = true;
                $overrideLocalValues = true;
            } else {
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
            }
        } else {
            $entity = $class->newInstance();
            $oid = spl*object*hash($entity);
            $this->_entityIdentifiers[$oid] = $id;
            $this->*entityStates[$oid] = self::STATE*MANAGED;
            $this->_originalEntityData[$oid] = $data;
            $this->_identityMap[$class->rootEntityName][$idHash] = $entity;
            if ($entity instanceof NotifyPropertyChanged) {
                $entity->addPropertyChangedListener($this);
            }
            $overrideLocalValues = true;
        }

In this case, the _identityMap is set so the originalEntityData is not initialized

I realized that identityMap was set while looping into the parent entity associations
Look again in UnitOfWork._createEntity()

 $newValue = $this->_em->getProxyFactory()->getProxy($assoc->targetEntityName, $associatedId);
// PERF: Inlined & optimized code from UnitOfWork#registerManaged()
$newValueOid = spl*object*hash($newValue);
$this->_entityIdentifiers[$newValueOid] = $associatedId;
$this->_identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue;
$this->*entityStates[$newValueOid] = self::STATE*MANAGED;

I will try to build you a UnitTest

Originally created by @doctrinebot on GitHub (Mar 18, 2010). Originally assigned to: @beberlei on GitHub. Jira issue originally created by user rickdt: Here is the pseudo-code to reproduce. Let's say we have 2 entity, Person and Phone. There is a OneToMany relation between Person and Phone. You get a person entity with the find() method: ``` $person = $em->find('Person', 1); $phones = $person->getPhones() $phone = $phones[0]; // Any would do $phone->setNumber('999-9999'); $em->persist($phone); $em->persist($person); $em->flush(); ``` If you look at the resulting update query, you will see that all fields get updated and not only the "number" field. This is due to the fact that originalEntityData is not loaded and the change set cannot be calculated properly. I noticed this problem because I need the originalEntityData for an other purpose (creating history records) and it break when I use proxies. Look at UnitOfWork._createEntity() ``` if (isset($this->_identityMap[$class->rootEntityName][$idHash])) { $entity = $this->_identityMap[$class->rootEntityName][$idHash]; $oid = spl*object*hash($entity); if ($entity instanceof Proxy && ! $entity->*_isInitialized_*) { $entity->*_isInitialized_* = true; $overrideLocalValues = true; } else { $overrideLocalValues = isset($hints[Query::HINT_REFRESH]); } } else { $entity = $class->newInstance(); $oid = spl*object*hash($entity); $this->_entityIdentifiers[$oid] = $id; $this->*entityStates[$oid] = self::STATE*MANAGED; $this->_originalEntityData[$oid] = $data; $this->_identityMap[$class->rootEntityName][$idHash] = $entity; if ($entity instanceof NotifyPropertyChanged) { $entity->addPropertyChangedListener($this); } $overrideLocalValues = true; } ``` In this case, the _identityMap is set so the originalEntityData is not initialized I realized that identityMap was set while looping into the parent entity associations Look again in UnitOfWork._createEntity() ``` $newValue = $this->_em->getProxyFactory()->getProxy($assoc->targetEntityName, $associatedId); // PERF: Inlined & optimized code from UnitOfWork#registerManaged() $newValueOid = spl*object*hash($newValue); $this->_entityIdentifiers[$newValueOid] = $associatedId; $this->_identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue; $this->*entityStates[$newValueOid] = self::STATE*MANAGED; ``` I will try to build you a UnitTest
admin added the Bug label 2026-01-22 12:42:13 +01:00
admin closed this issue 2026-01-22 12:42:13 +01:00
Author
Owner

@doctrinebot commented on GitHub (Mar 18, 2010):

Comment created by rickdt:

The attached UnitTest does not work for two reason

  1. I tried these steps to test the problem
  • Create test data
  • clear the EntityManager
  • Query for the data with find
  • Update the entity obtained by find

I expected the entity to be a Proxy but it is a standard entity. Moreover, it have the same spl_object_hash than the object initially created (which have been cleared)

  1. I forgot one important detail in the pre-conditions. There is two relations between Person and Phone

Person->phones (one to many)
Person->main_phone (one to one)

There is no such case in the provided test models

@doctrinebot commented on GitHub (Mar 18, 2010): Comment created by rickdt: The attached UnitTest does not work for two reason 1) I tried these steps to test the problem - Create test data - clear the EntityManager - Query for the data with find - Update the entity obtained by find I expected the entity to be a Proxy but it is a standard entity. Moreover, it have the same spl_object_hash than the object initially created (which have been cleared) 2) I forgot one important detail in the pre-conditions. There is two relations between Person and Phone Person->phones (one to many) Person->main_phone (one to one) There is no such case in the provided test models
Author
Owner

@doctrinebot commented on GitHub (Mar 24, 2010):

Comment created by rickdt:

I managed to bypass the problem using eager fetch (fetch="EAGER") in my associations.

@doctrinebot commented on GitHub (Mar 24, 2010): Comment created by rickdt: I managed to bypass the problem using eager fetch (fetch="EAGER") in my associations.
Author
Owner

@doctrinebot commented on GitHub (Mar 28, 2010):

Comment created by @beberlei:

Attached a test myself, i can't reproduce the issue with both types of proxies. Both tests pass!

@doctrinebot commented on GitHub (Mar 28, 2010): Comment created by @beberlei: Attached a test myself, i can't reproduce the issue with both types of proxies. Both tests pass!
Author
Owner

@doctrinebot commented on GitHub (Mar 28, 2010):

Comment created by @beberlei:

Btw it is correct behaviour that originalEntityData is EMPTY so long the proxy is not loaded.

@doctrinebot commented on GitHub (Mar 28, 2010): Comment created by @beberlei: Btw it is correct behaviour that originalEntityData is EMPTY so long the proxy is not loaded.
Author
Owner

@doctrinebot commented on GitHub (Mar 29, 2010):

Comment created by rickdt:

It's obvious that originalEntityData cannot be filled until the proxy is loaded.

I was shure it was loaded when I saw the empty originalData. Maybe I did not check correctly.

I'm not able for now to reproduce the problem in a simple unit test. The context in which it occurs in my application is fairly complex and as I said, work fine with eager fetching.

I can't affort to spend more time on that just now. You can close the Case if you want, I will reopen it if I get more pertinent informations.

Thank You

@doctrinebot commented on GitHub (Mar 29, 2010): Comment created by rickdt: It's obvious that originalEntityData cannot be filled until the proxy is loaded. I was shure it was loaded when I saw the empty originalData. Maybe I did not check correctly. I'm not able for now to reproduce the problem in a simple unit test. The context in which it occurs in my application is fairly complex and as I said, work fine with eager fetching. I can't affort to spend more time on that just now. You can close the Case if you want, I will reopen it if I get more pertinent informations. Thank You
Author
Owner

@doctrinebot commented on GitHub (Mar 29, 2010):

Comment created by @beberlei:

Updated to Minor and removed scheduled version until we can find a reproduce case for this bug.

@doctrinebot commented on GitHub (Mar 29, 2010): Comment created by @beberlei: Updated to Minor and removed scheduled version until we can find a reproduce case for this bug.
Author
Owner

@doctrinebot commented on GitHub (May 12, 2010):

Comment created by rickdt:

I finally managed to write a valid test case. The detail of the problem are written in comments in the test case file.

I think this will be enough for you to work on the problem.

BTW, Doctrine 2 beta 1 work great in our production environnement. Your great work is really appreciated.

@doctrinebot commented on GitHub (May 12, 2010): Comment created by rickdt: I finally managed to write a valid test case. The detail of the problem are written in comments in the test case file. I think this will be enough for you to work on the problem. BTW, Doctrine 2 beta 1 work great in our production environnement. Your great work is really appreciated.
Author
Owner

@doctrinebot commented on GitHub (May 15, 2010):

Comment created by @beberlei:

Woah! thanks for the test-case, this was indeed a very nasty bug and it is now fixed.

@doctrinebot commented on GitHub (May 15, 2010): Comment created by @beberlei: Woah! thanks for the test-case, this was indeed a very nasty bug and it is now fixed.
Author
Owner

@doctrinebot commented on GitHub (May 15, 2010):

Issue was closed with resolution "Fixed"

@doctrinebot commented on GitHub (May 15, 2010): Issue was closed with resolution "Fixed"
Author
Owner

@doctrinebot commented on GitHub (Dec 13, 2015):

Imported 3 attachments from Jira into https://gist.github.com/5d4a9f1777bc45c62254

@doctrinebot commented on GitHub (Dec 13, 2015): Imported 3 attachments from Jira into https://gist.github.com/5d4a9f1777bc45c62254 - [10495_DDC440Test.php](https://gist.github.com/5d4a9f1777bc45c62254#file-10495_DDC440Test-php) - [10524_DDC440Test.php](https://gist.github.com/5d4a9f1777bc45c62254#file-10524_DDC440Test-php) - [10604_DDC440Test.php](https://gist.github.com/5d4a9f1777bc45c62254#file-10604_DDC440Test-php)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#551