orm: Order of referenced child deletions not correct when referencing to itself

Bug Report

Q A
BC Break no
Version 2.14.0

Summary

The order in which the UoW wants to delete children is somehow missing a dependency when there is an association to the same class even if you specified cascade: ['remove']. Given you have

  • Parent -> has an association to children with cascade: ['remove']
  • Child 1
  • Child 2 -> has an association to Child 1 with cascade: ['remove'].

Now you delete the parent. Doctrine tries to remove Child 1 first instead of Child 2 causing a foreign constraint violation:

Uncaught PDOException: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (test.child_entities, CONSTRAINT FK_DAEB194156A273CC FOREIGN KEY (origin_id) REFERENCES child_entities (id))

How to reproduce

I’ve created a test setup because I’m not familiar with the internals of ORM at all. So here we go:

  1. Clone https://github.com/Toflar/doctrine-orm-bug-reproducer
  2. Run composer install
  3. Adjust dummy mysql connection example in bootstrap.php.
  4. Run bin/doctrine orm:schema-tool:drop --force && bin/doctrine orm:schema-tool:create
  5. Run php test.php.

Expected behavior

It should not throw an exception. Doctrine should remove Child 2 first.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 15 (12 by maintainers)

Commits related to this issue

Most upvoted comments

I’ve taken a closer look at this and in fact, what you’ve found here is a variant of the deletion case from #10531:

graph LR;
    Child1 --> Parent;
    Child2 --> Parent;
    Child2 --> Child1;

Both associations (from Child to Parent as well as from Child to Child) are cascade: delete, so trying to delete the Parent instance will setup the entire graph for deletion.

All associations are nullable in the database, but that’s of no relevance for the delete case, since the ORM does not currently use an “extra update” before DELETE to break cycles.

There is no database-level ON DELETE SET NULL, so the ORM will have to find a valid deletion order by itself.

This is, in fact, possible by working through Child2, Child1, Parent. But, the current 2.14.x code only looks at associations at the table level, deleting child rows before parent. It does not honor that a particular order must be followed between the entities of the child table itself. This is the #10531 issue, and it will be fixed by #10547.