Description
Bug Report
Q | A |
---|---|
BC Break | no |
Version | 2.6.3 |
Summary
Symptom: Unable to update the parent of an entity when that entity was loaded via a query from the parent including the children through a join and inclusion in the select list.
Deeper: Hydration of child entities in the UnitOfWork::$originalEntityData during a query that includes the children as part of it does not fully hydrate parent relationships. Specifically, it doesn't hydrate the parent relationship that the child was loaded through.
This causes issues where computing the change set of an entity who was loaded in this way and their parent was changed causes this change to be missed.
From the UnitOfWork.php lines 2686:
if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
continue;
}
Appears to skip hydrating the parent relationship because it's in the hint list
Current behavior
The parent property cannot be changed on the child entities loaded this way as:
The UnitOfWork::$originalEntityData contains a property parent_id = #
as the relationship is not hydrated to the proper field parent
. When the parent
property is changed using the entity and persisted no change will be detected as the compute change set won't find the property in the copy coming from $originalEntityData
How to reproduce
entity Parent {
Id
has-many children of Child
}
entity Child {
Id
belongs-to parent of Parent
}
// Assume ::getRepository() is equiv to getEntityManager()->getRepository(Parent)
$parentEntity = Parent::getRepository()->createQueryBuilder('p')
->leftJoin('p.children', 'c', 'WITH')
->addSelect(['c'])
->where('p.id = :parent_id')
->setParameter('parent_id', X)
->getQuery()->getResult();
// Assume ::load is a pass through to ->find(ID)
$targetParent = Parent::load(Y);
foreach ($parentEntity->children as $child) {
$child->parent = $targetParent;
$child->persist();
}
flush()
Expected behavior
The parent of the child entity should have changed from the original X to the target Y