Skip to content

Unable to update belongs-to relationship when loaded through query from the parent (incomplete hydration) #7812

Open
@matt-stuart

Description

@matt-stuart

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions