Open karlosss opened 1 month ago
As you already figured there's no good way of making this work without changing EF code.
This is related to https://github.com/dotnet/efcore/issues/1699
However this case might be easier to support. We already have https://github.com/dotnet/efcore/blob/c78dc6c566c7ac1231b9b834f45877c83f4be9b5/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs#L1357 to indicate dependencies that can be broken. We just need to add metadata for FKs that are either non-enforced within a transaction or the enforcement can be temporarily suspended if necessary.
Hi @AndriySvyryd, thank you for your reply! By any chance, is there any timeline when I can expect this to be done, or are you rather saying that it would be possible to support, however there are no plans any time soon?
or are you rather saying that it would be possible to support, however there are no plans any time soon?
Yes. This won't be implemented for 9.0
Imagine a data model with two entities, companies and people. A person works for exactly one company and a company has multiple employees. A company also must have a manager, who is an employee of that company.
This is a chicken-and-egg problem: to create a company, its manager has to exist, and for the manager to exist, the company has to exist. So in EF (I am on v8.0.6) I created the following models (not sure if relevant, I am using lazy loading proxies):
and the following configurations:
Then I generated the migrations, from where I deleted all constraints and replaced them with deferred constraints so that I am able to create any records in my database (I am using postgreSQL):
Now, I am able to insert records to my DB in SQL:
When I try the same thing in EF, I actually got further than I expected. The
Add
to db context works flawlessly, just EF refuses to even try to save, because it thinks that because of the dependency loop, the save will not work out.So I went further and found out I can intercept the part of EF where it is trying to determine the order of the statements so that it would work with immediate constraints:
Here I wrote my own "topological sort" that just returns the commands in whatever order. And then, in my database logs, I see a transaction with two insert statements that successfully commits.
This solution, however, would require all constrains in my database to be deferrable, which is not what is desired. Is there an easy way how to break loops in the internal topological sort? When I tried, I found out that the
Multigraph
class is internal in EF and many methods on theCommandBatchPreparer
are private. I could probably still access these via reflection, but I have a feeling that I am already hacking into EF more than enough...Is there an easy way how to achieve this, or I would need to write my own topological sort for this that would handle the loops somehow?
PS: retrieving the data from the database with EF works flawlessly