-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Order of referenced child deletions not correct when referencing to itself #10348
Comments
This test is based on @Toflar ' s reproducer and can be picked up: |
Thanks <3 Maybe sqlite is configured without foreign key support in the CI? 🤔 |
I just tested local on mac. This could be the reason. Maybe it even fails in CI. :) EDIT: |
@Toflar could you please have a look at #10547? I am not too confident it might fix this issue here, since I do not know if all the entities that need to be cascade-deleted are put into the But anyway, you might want to give it a shot. |
Ah, maybe this is #10548? |
Hey @mpdude wow, the other PR is some impressive work! Maybe we can pick up @simonberger's reproducer (simonberger@2abff4c) in the CI as well, then we know if your PR fixes the problem :) |
That's great news, although I am not sure if that's by incident. But I have this issue on my shortlist and think it can be fixed as well. For the delete case, we need not look out for nullable associations (like we do at insert time), but find the associations that use |
While I don't have much knowledge about the implementation, the test at least looked senseful to me and should have some validity. |
Definitely, it is! I did not want to put that into question, sorry if it sounded like that. My thinking was that I see another problematic case pointed out by this issue here, and I think #10547 does not address this precisely enough. I’ll see if I can fine-tune the test a little to make it fail until that situation is addressed as well. Thank you for the PR against my branch, that helps. |
I also didn't read it like this and the tests are from toflar, I just converted them to phpunit. |
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 All associations are There is no database-level This is, in fact, possible by working through |
Co-authored-by: Matthias Pigulla <mp@webfactory.de>
Wohoo! Thanks so much for the investigation and the awesome work - that PR seems to solve a lot of issues! Kudos @mpdude! Let's hope your work can make it to a release soon! |
Test case included at 3917692 |
Indeed there is another bug regarding the delete order, which I have filed as #10566 |
Co-authored-by: Matthias Pigulla <mp@webfactory.de>
Co-authored-by: Matthias Pigulla <mp@webfactory.de>
This is part of the series of issues fixed by doctrine#10547. In particular, the changes from doctrine#10566 were relevant. See doctrine#10348 for the bug description. Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
This is part of the series of issues fixed by doctrine#10547. In particular, the changes from doctrine#10566 were relevant. See doctrine#10348 for the bug description. Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
This is part of the series of issues fixed by doctrine#10547. In particular, the changes from doctrine#10566 were relevant. See doctrine#10348 for the bug description. Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
Add a test case to show #10348 has been fixed
…ion (#10913) 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 NULL` or `... CASCADE` need 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, `odc` means `ON DELETE CASCADE`, and `ref` is a regular foreign key with no extra `ON DELETE` semantics. ```mermaid graph LR; C-->|ref| B; B-->|odc| A; ``` 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. ```mermaid graph LR; A-->|odc| B; B-->|odc| A; C-->|ref| B; ``` 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. ```mermaid graph LR; A-->|odc| B; B-->|odc| A; A-->|ref| C; C-->|ref| B; ``` This example has no possible remove order. But, if we treat `odc` edges as optional, A -> C -> B would wrongly be deemed suitable. ```mermaid graph LR; A-->|ref| B; B-->|odc| C; C-->|odc| B; D-->|ref| C; ``` Here, we must first remove A and D in any order; then, B and C in any order. If we treat one of the `odc` edges 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 CASCADE` associations between those entities. Then, use [Tarjan's algorithm](https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_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 NULL` can 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.
Bug Report
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
cascade: ['remove']
cascade: ['remove']
.Now you delete the parent.
Doctrine tries to remove Child 1 first instead of Child 2 causing a foreign constraint violation:
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:
composer install
bootstrap.php
.bin/doctrine orm:schema-tool:drop --force && bin/doctrine orm:schema-tool:create
php test.php
.Expected behavior
It should not throw an exception. Doctrine should remove Child 2 first.
The text was updated successfully, but these errors were encountered: