mirror of
https://github.com/doctrine/orm.git
synced 2026-03-23 22:42:18 +01:00
[2.10.2] Ignore dependencies having onDelete="SET NULL" when computing commit order for removal operations #6874
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @DoobleD on GitHub (Nov 19, 2021).
Feature Request
Summary
TLDR: Doctrine could find a valid delete commit order in some circular references cases if it were ignoring dependencies with
onDelete="SET NULL".I have 3 entities with the following relationships:
OneToManyto B withcascade={"remove"}.OneToManyto C withcascade={"remove"}.OneToOneto C with no inverse side,nullable=trueandonDelete="SET NULL".When I remove A via the entity manager, I get a foreign key violation error because the commit order Doctrine computes is B, C, A. Indeed B can't be deleted first since it is referenced by C.
I expected the order to be C, B, A instead. That wouldn't violate FK constraints. I eventually realized I have a circular reference (A references C and C references A via B) and that Doctrine doesn't know how to deal with it.
The thing is, the circular reference is not really one when deleting, because of
onDelete="SET NULL". If Doctrine were to ignore such dependencies on delete, the commit order would end up correct.Is there any chance this could be implemented?
Disclaimer: I'm not very familiar with Doctrine and DB engines in general, there could be downsides I'm not seeing.
More precisely what happens
UnitOfWork::getCommitOrdercorrectly lists the dependencies for each nodes:The order in which nodes are listed (C, B, A), comes from
UnitOfWork::doRemove's recursion putting the most deeply nested child first in the deletion list, and working back towards the parents.Note in particular the dep A in C. It comes from the
OneToOnerelationship between A and C (the one withonDelete="SET NULL").A bit later in
CommitOrderCalculator::visit(which computes the actual commit order from the dependency list):Thus the order of
CommitOrderCalculator::sortedNodeListends up being: B, C, A. That order is reversed then again is used in reversed (i.e. original order).When dependencies are first listed, Doctrine could ignore the dep A in C because that dep has
onDelete="SET NULL". The whole process would then compute a valid commit order C, B, A.@DoobleD commented on GitHub (Nov 19, 2021):
Another way of making this work would be to support deferrable constraints, but Doctrine seems to have issues with that.
@DoobleD commented on GitHub (Nov 19, 2021):
Another (probably bad) workaround is to add
onDelete="CASCADE"on theManyToOnelink to B in C. That seems to work, though I keepcascade={"remove"}on theOneToManyside because I need lifecycle events.@DoobleD commented on GitHub (Nov 19, 2021):
I ended up removing all
onDeleteannotations and set deferred constraints on all my foreign keys instead.This is much simpler to manage, and hopefully #3423 will get solved soon (there seem to be a PR with recent activity at least).
@mpdude commented on GitHub (Feb 27, 2023):
Could you please test if #10547 solves the problem for you?