DDC-1879: Orphans are neither nulled nor removed when merging a graph of detached entities #2370

Open
opened 2026-01-22 13:50:40 +01:00 by admin · 5 comments
Owner

Originally created by @doctrinebot on GitHub (Jun 18, 2012).

Originally assigned to: @beberlei on GitHub.

Jira issue originally created by user systho:

When merging a graph of detached entities, the created entitied are created and the updated entities are updated but the non-present entities (which exist in the database but are not in the graph) are neither removed nor have them their association column nullified.

Example :

In my code I have 2 entities : Parent and Child. There is a OneToMany(cascade={"all"}, orphanRemoval=true) relation defined in Parent.

In my database I have a Parent row with an id of 1, which has 3 Children with ids 1,2,3.

When I write the following code, I expect the Parent with id 1 and the Child with id 2 to be updated, a new Child to be created and the Child with id 1 and 3 to be deleted.

$parent = new Parent(); $parent->id = 1  // detached entity
$existing_child = new Child(); $child->id = 2 // detached entity
$new_child = new Child(); // new entity
$dinner->addChild($existing_child);
$dinner->addChild($new_child);

$em->merge($dinner);

$em->flush();

The objects I expect to be created and updated have the correct behaviour but the old children are not touched, they are still present in the database.

Originally created by @doctrinebot on GitHub (Jun 18, 2012). Originally assigned to: @beberlei on GitHub. Jira issue originally created by user systho: When merging a graph of detached entities, the created entitied are created and the updated entities are updated but the non-present entities (which exist in the database but are not in the graph) are neither removed nor have them their association column nullified. Example : In my code I have 2 entities : Parent and Child. There is a OneToMany(cascade={"all"}, orphanRemoval=true) relation defined in Parent. In my database I have a Parent row with an id of 1, which has 3 Children with ids 1,2,3. When I write the following code, I expect the Parent with id 1 and the Child with id 2 to be updated, a new Child to be created and the Child with id 1 and 3 to be deleted. ``` $parent = new Parent(); $parent->id = 1 // detached entity $existing_child = new Child(); $child->id = 2 // detached entity $new_child = new Child(); // new entity $dinner->addChild($existing_child); $dinner->addChild($new_child); $em->merge($dinner); $em->flush(); ``` The objects I expect to be created and updated have the correct behaviour but the old children are not touched, they are still present in the database.
admin added the Bug label 2026-01-22 13:50:40 +01:00
Author
Owner

@doctrinebot commented on GitHub (Jan 23, 2013):

Comment created by @ocramius:

I don't think this is valid. Orphan removal scheduling is handled only when an unit of work is available.

What's the state of $dinner before your example? Can you var_dump it?

@doctrinebot commented on GitHub (Jan 23, 2013): Comment created by @ocramius: I don't think this is valid. Orphan removal scheduling is handled only when an unit of work is available. What's the state of `$dinner` before your example? Can you `var_dump` it?
Author
Owner

@MatthiasKuehneEllerhold commented on GitHub (Nov 3, 2017):

@Ocramius I've ran into the same problem today. So I guess this issue is still relevant?

I guess $dinner was meant to be $parent in systho example?
$parent has ID 1 and an ArrayCollection (I guess?) with just the two childs:

  • existing child (ID 2)
  • and new child (without an ID yet)

Our expections are:

  • the child with ID 2 should get updated
  • the new child should get inserted (probably ID 4)
  • the children 1 & 3 to be deleted

What I've tried:

$dbParent = $em->getRepository(..)->find(1);
echo $dbParent->getChildren()->count(); // echos '3'

echo $parent->getChildren()->count(); // echos '2'
$newDbParent = $em->merge($parent);
$em->flush();

echo $newDbParent->getChildren()->count(); // echos '2' as expected

But the obsolete children were never deleted from the database.
I hooked up an SQL query logger to doctrine and there are only UPDATE & INSERT queries in it, the DELETE queries are missing.

Mapping annotation of $children in class Parent:

    /**
     * @var Child[]|ArrayCollection
     * @ORM\OneToMany(
     *     targetEntity="Child",
     *     mappedBy="parent",
     *     cascade={"all"},
     *     orphanRemoval=true,
     *     fetch="EAGER"
     * )
     */
    protected $children;

Mapping annotation of $parent in class Child:

    /**
     * @var Parent
     * @ORM\ManyToOne(targetEntity="Parent", inversedBy="children", cascade={"all"})
     * @ORM\JoinColumn(name="parent", referencedColumnName="id", nullable=false)
     */
    protected $parent;

I'm using doctrine/orm in a zend-expressive project with these versions:

dasprid/container-interop-doctrine       1.0.0             
doctrine/annotations                     v1.5.0            
doctrine/cache                           v1.7.1            
doctrine/collections                     v1.5.0            
doctrine/common                          v2.8.1            
doctrine/dbal                            v2.6.2            
doctrine/inflector                       v1.2.0            
doctrine/instantiator                    1.1.0             
doctrine/lexer                           v1.0.1            
doctrine/orm                             v2.5.12 
@MatthiasKuehneEllerhold commented on GitHub (Nov 3, 2017): @Ocramius I've ran into the same problem today. So I guess this issue is still relevant? I guess `$dinner` was meant to be `$parent` in systho example? `$parent` has ID 1 and an `ArrayCollection` (I guess?) with just the two childs: * existing child (ID 2) * and new child (without an ID yet) Our expections are: * the child with ID 2 should get updated * the new child should get inserted (probably ID 4) * the children 1 & 3 to be deleted What I've tried: ``` $dbParent = $em->getRepository(..)->find(1); echo $dbParent->getChildren()->count(); // echos '3' echo $parent->getChildren()->count(); // echos '2' $newDbParent = $em->merge($parent); $em->flush(); echo $newDbParent->getChildren()->count(); // echos '2' as expected ``` But the obsolete children were never deleted from the database. I hooked up an SQL query logger to doctrine and there are only `UPDATE` & `INSERT` queries in it, the `DELETE` queries are missing. Mapping annotation of `$children` in class `Parent`: ``` /** * @var Child[]|ArrayCollection * @ORM\OneToMany( * targetEntity="Child", * mappedBy="parent", * cascade={"all"}, * orphanRemoval=true, * fetch="EAGER" * ) */ protected $children; ``` Mapping annotation of `$parent` in class `Child`: ``` /** * @var Parent * @ORM\ManyToOne(targetEntity="Parent", inversedBy="children", cascade={"all"}) * @ORM\JoinColumn(name="parent", referencedColumnName="id", nullable=false) */ protected $parent; ``` I'm using doctrine/orm in a zend-expressive project with these versions: ``` dasprid/container-interop-doctrine 1.0.0 doctrine/annotations v1.5.0 doctrine/cache v1.7.1 doctrine/collections v1.5.0 doctrine/common v2.8.1 doctrine/dbal v2.6.2 doctrine/inflector v1.2.0 doctrine/instantiator 1.1.0 doctrine/lexer v1.0.1 doctrine/orm v2.5.12 ```
Author
Owner

@lcobucci commented on GitHub (Nov 26, 2017):

@MatthiasKuehneEllerhold could you please send us a failing test case that reproduces that behaviour? It would help us a lot to identify and fix the issue you're describing.

You can find examples on 388afb46d0/tests/Doctrine/Tests/ORM/Functional/Ticket

@lcobucci commented on GitHub (Nov 26, 2017): @MatthiasKuehneEllerhold could you please send us a failing test case that reproduces that behaviour? It would help us a lot to identify and fix the issue you're describing. You can find examples on https://github.com/doctrine/doctrine2/tree/388afb46d0cb3ed0c51332e8df0de9e942c2690b/tests/Doctrine/Tests/ORM/Functional/Ticket
Author
Owner

@MatthiasKuehneEllerhold commented on GitHub (Nov 27, 2017):

I've opened a PR with a failing test case for this: https://github.com/doctrine/doctrine2/pull/6850 .

@MatthiasKuehneEllerhold commented on GitHub (Nov 27, 2017): I've opened a PR with a failing test case for this: https://github.com/doctrine/doctrine2/pull/6850 .
Author
Owner

@Liiva commented on GitHub (Nov 19, 2018):

I'm running into the same issue. In the PR it is mentioned this might be fixed in version 2.6 but as we're using 2.7.1 I assume this is not the case. Any updates on this issue?

I've created a separate repo with a reproducible case here.

@Liiva commented on GitHub (Nov 19, 2018): I'm running into the same issue. In the PR it is mentioned this might be fixed in version 2.6 but as we're using 2.7.1 I assume this is not the case. Any updates on this issue? I've created a separate repo with a reproducible case [here](https://github.com/Liiva/unidirectional-one-to-many-merge-issue).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#2370