DDC-518: Merging an entity with a one to one association to a MANAGED entity with no id throws 'The given entity has no identity.' #645

Closed
opened 2026-01-22 12:45:32 +01:00 by admin · 8 comments
Owner

Originally created by @doctrinebot on GitHub (Apr 13, 2010).

Jira issue originally created by user ccapndave:

Calling merge($entity) where $entity has a one to one association to another entity that has been persisted but not yet flushed (when using auto-generated ids) throws 'The given entity has no identity.'

It looks like it does this because _doMerge in UnitOfWork assumes for one to one associations only that the associated entity has an id and calls registerManaged, which then calls addToIdentityMap)on it.

I think that registeredManaged should only be called if !isset($this->_entityInsertions[spl_object_hash($other)])

// This is a new element
$doctor = new \vo\Doctor(); $d1->name = "New doctor";

// This is a detached element which is in the database
$patient = new \vo\Patient(); $p1->name = "Existing patient"; $p1->id = 1;

$doctor->patients->add($patient);
$patient ->doctor = $doctor;

$em->persist($doctor);

// This throws InvalidArgumentException: The given entity has no identity. in D:\Projects\ORM\flextrine2\flextrine\web\lib\Doctrine\ORM\UnitOfWork.php on line 1014
$em->merge($patient);
class Doctor {

    /*** @Id @Column(type="integer") @GeneratedValue(strategy="IDENTITY") **/
    public $id;

    /*** @Column(length=100, type="string") **/
    public $name;

    /****
     * @OneToMany(targetEntity="Patient", mappedBy="doctor", fetch="EAGER")
     */
    public $patients;

    public function **construct() {
        $this->patients = new ArrayCollection();
    }

}
class Patient {

    var $_explicitType = "vo/Patient";

    /*** @Id @Column(type="integer") @GeneratedValue(strategy="IDENTITY") **/
    public $id;

    /*** @Column(length=100, type="string") **/
    public $name;

    /****
     * @OneToOne(targetEntity="Doctor", inversedBy="patients")
     * @JoinColumn(name="doctor_id", referencedColumnName="id")
     */
    public $doctor;

}
Originally created by @doctrinebot on GitHub (Apr 13, 2010). Jira issue originally created by user ccapndave: Calling merge($entity) where $entity has a one to one association to another entity that has been persisted but not yet flushed (when using auto-generated ids) throws 'The given entity has no identity.' It looks like it does this because _doMerge in UnitOfWork assumes for one to one associations only that the associated entity has an id and calls registerManaged, which then calls addToIdentityMap)on it. I think that registeredManaged should only be called if !isset($this->_entityInsertions[spl_object_hash($other)]) ``` // This is a new element $doctor = new \vo\Doctor(); $d1->name = "New doctor"; // This is a detached element which is in the database $patient = new \vo\Patient(); $p1->name = "Existing patient"; $p1->id = 1; $doctor->patients->add($patient); $patient ->doctor = $doctor; $em->persist($doctor); // This throws InvalidArgumentException: The given entity has no identity. in D:\Projects\ORM\flextrine2\flextrine\web\lib\Doctrine\ORM\UnitOfWork.php on line 1014 $em->merge($patient); ``` ``` class Doctor { /*** @Id @Column(type="integer") @GeneratedValue(strategy="IDENTITY") **/ public $id; /*** @Column(length=100, type="string") **/ public $name; /**** * @OneToMany(targetEntity="Patient", mappedBy="doctor", fetch="EAGER") */ public $patients; public function **construct() { $this->patients = new ArrayCollection(); } } ``` ``` class Patient { var $_explicitType = "vo/Patient"; /*** @Id @Column(type="integer") @GeneratedValue(strategy="IDENTITY") **/ public $id; /*** @Column(length=100, type="string") **/ public $name; /**** * @OneToOne(targetEntity="Doctor", inversedBy="patients") * @JoinColumn(name="doctor_id", referencedColumnName="id") */ public $doctor; } ```
admin added the Bug label 2026-01-22 12:45:32 +01:00
admin closed this issue 2026-01-22 12:45:34 +01:00
Author
Owner

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

Comment created by romanb:

I think the order of operations in your example is not correct even though the error is misleading.

You are associating a "new doctor" to a "detached patient". That does not seem right, remember that merge() returns a managed copy, thus when merging the patient later, the "new doctor" is still associated with the "detached patient", not with the managed one.

The following should work:

// Merge detached patient
$managedPatient = $em->merge($patient);

// Associate new doctor with patient
$doctor->patients->add($managedPatient);
$managedPatient->doctor = $doctor;

// Persist new doctor and flush
$em->persist($doctor);
$em->flush();
@doctrinebot commented on GitHub (May 8, 2010): Comment created by romanb: I think the order of operations in your example is not correct even though the error is misleading. You are associating a "new doctor" to a "detached patient". That does not seem right, remember that merge() returns a managed copy, thus when merging the patient later, the "new doctor" is still associated with the "detached patient", not with the managed one. The following should work: ``` // Merge detached patient $managedPatient = $em->merge($patient); // Associate new doctor with patient $doctor->patients->add($managedPatient); $managedPatient->doctor = $doctor; // Persist new doctor and flush $em->persist($doctor); $em->flush(); ```
Author
Owner

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

Comment created by ccapndave:

You are quite right - that does work.

However, I am now trying to implement my use case (turning a tree of detached objects into a tree of managed objects) and implementing the correct order you describe above seems to cause another problem. I am not sure if this should be another ticket, but I'll put it here for the moment.

Note that the part within the stars that creates the unmanaged doctor and the detached patient simulates exactly what is received by Doctrine in my application so I can't put any merges in here.

/**********************************************************************/
// This is a new element
$doctor = new \vo\Doctor(); $doctor->name = "New doctor";

// This is a detached element which is in the database
$patient = new \vo\Patient(); $patient->name = "Existing patient"; $patient->id = 1;

$doctor->patients->add($patient); $patient->doctor = $doctor;
/**********************************************************************/

// Now replace $patient with its managed version
$managedPatient = $em->merge($patient);
$doctor->patients->set(0, $managedPatient);

// Persist the doctor
$em->persist($doctor);

$em->flush();

This works up to the flush, which throws an error of the form:

Notice: Undefined index: 000000007dd346c3000000005d0908d2 in \Doctrine\ORM\UnitOfWork.php on line 1955

In the database this results in a new doctor being created, but doctor_id in the patients table is set to NULL for the patient that is supposed to be linking to it.

@doctrinebot commented on GitHub (May 16, 2010): Comment created by ccapndave: You are quite right - that does work. However, I am now trying to implement my use case (turning a tree of detached objects into a tree of managed objects) and implementing the correct order you describe above seems to cause another problem. I am not sure if this should be another ticket, but I'll put it here for the moment. Note that the part within the stars that creates the unmanaged doctor and the detached patient simulates exactly what is received by Doctrine in my application so I can't put any merges in here. ``` /**********************************************************************/ // This is a new element $doctor = new \vo\Doctor(); $doctor->name = "New doctor"; // This is a detached element which is in the database $patient = new \vo\Patient(); $patient->name = "Existing patient"; $patient->id = 1; $doctor->patients->add($patient); $patient->doctor = $doctor; /**********************************************************************/ // Now replace $patient with its managed version $managedPatient = $em->merge($patient); $doctor->patients->set(0, $managedPatient); // Persist the doctor $em->persist($doctor); $em->flush(); ``` This works up to the flush, which throws an error of the form: Notice: Undefined index: 000000007dd346c3000000005d0908d2 in \Doctrine\ORM\UnitOfWork.php on line 1955 In the database this results in a new doctor being created, but doctor_id in the patients table is set to NULL for the patient that is supposed to be linking to it.
Author
Owner

@doctrinebot commented on GitHub (Jun 6, 2010):

Comment created by @beberlei:

I think this can't work, because obviously $doctor->patients still points to the unmanaged $patient, not the managed one.

Can you elaborate on why the star part is done by Doctrine? Where is doctrine doing that? what are you doing with the public API?

All the detached entities should be merged before doing anything regarding a NEW entity in my opinion.

@doctrinebot commented on GitHub (Jun 6, 2010): Comment created by @beberlei: I think this can't work, because obviously $doctor->patients still points to the unmanaged $patient, not the managed one. Can you elaborate on why the star part is done by Doctrine? Where is doctrine doing that? what are you doing with the public API? All the detached entities should be merged before doing anything regarding a NEW entity in my opinion.
Author
Owner

@doctrinebot commented on GitHub (Jun 6, 2010):

Comment created by @beberlei:

Moved to beta3 for now

@doctrinebot commented on GitHub (Jun 6, 2010): Comment created by @beberlei: Moved to beta3 for now
Author
Owner

@doctrinebot commented on GitHub (Jun 6, 2010):

Comment created by @beberlei:

Patch with test-case for this merging scenario

@doctrinebot commented on GitHub (Jun 6, 2010): Comment created by @beberlei: Patch with test-case for this merging scenario
Author
Owner

@doctrinebot commented on GitHub (Jul 30, 2010):

Comment created by romanb:

Fixed in 69073c4b37

@doctrinebot commented on GitHub (Jul 30, 2010): Comment created by romanb: Fixed in http://github.com/doctrine/doctrine2/commit/69073c4b37ee28f988306db4965f512b70f45181
Author
Owner

@doctrinebot commented on GitHub (Jul 30, 2010):

Issue was closed with resolution "Fixed"

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

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

Imported 1 attachments from Jira into https://gist.github.com/f86063ebfb3c36dac12a

@doctrinebot commented on GitHub (Dec 13, 2015): Imported 1 attachments from Jira into https://gist.github.com/f86063ebfb3c36dac12a - [10629_ddc518.patch](https://gist.github.com/f86063ebfb3c36dac12a#file-10629_ddc518-patch)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#645