Details
Description
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)])
Reproduce.php
// 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);
Doctor.php
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();
}
}
Patient.php
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;
}
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: