mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 06:52:09 +01:00
[PR #10913] Include ON DELETE CASCADE associations in the delete order computation
#12693
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?
Original Pull Request: https://github.com/doctrine/orm/pull/10913
State: closed
Merged: Yes
In order to resolve #10348, some changes were included in #10547 to improve the computed delete order for entities.
One assumption was that foreign key references with
ON DELETE SET NULLor... CASCADEneed not need to be taken into consideration when planning the deletion order, since the RDBMS would unset or cascade-delete such associations by itself when necessary. Only associations that do not use RDBMS-level cascade handling would be sequenced, to make sure the referring entity is deleted before the referred-to one.This assumption is wrong for
ON DELETE CASCADE. The following examples give reasons why we need to also consider such associations, and in addition, we need to be able to deal with cycles formed by them.In the following diagrams,
odcmeansON DELETE CASCADE, andrefis a regular foreign key with no extraON DELETEsemantics.In this example, C must be removed before B and A. If we ignore the B->A dependency in the delete order computation, the result may not to be correct. ACB is not a working solution.
This is the situation in #10912. We have to deal with a cycle in the graph. C must be removed before A as well as B. If we ignore the B->A dependency (e.g. because we set it to "optional" to get away with the cycle), we might end up with an incorrect order ACB.
This example has no possible remove order. But, if we treat
odcedges as optional, A -> C -> B would wrongly be deemed suitable.Here, we must first remove A and D in any order; then, B and C in any order. If we treat one of the
odcedges as optional, we might find the invalid solutions ABDC or DCAB.Solution implemented in this PR
First, build a graph with a node for every to-be-removed entity, and edges for
ON DELETE CASCADEassociations between those entities. Then, use Tarjan's algorithm to find strongly connected components (SCCs) in this graph. The significance of SCCs is that whenever we remove one of the entities in a SCC from the database (no matter which one), the DBMS will immediately remove all the other entities of that group as well.For every SCC, pick one (arbitrary) entity from the group to represent all entities of that group.
Then, build a second graph. Again we have nodes for all entities that are to be removed. This time, we insert edges for all regular (foreign key) associations and those with
ON DELETE CASCADE.ON DELETE SET NULLcan be left out. The edges are not added between the entities themselves, but between the entities representing the respective SCCs.Also, for all non-trivial SCCs (those containing more than a single entity), add dependency edges to indicate that all entities of the SCC shall be processed after the entity representing the group. This is to make sure we do not remove a SCC inadvertedly by removing one of its entities too early.
Run a topological sort on the second graph to get the actual delete order. Cycles in this second graph are a problem, there is no delete order.
Fixes #10912.