Can't save entity with auto-join: Unable to determine a valid ordering for dependent operations

StackOverflow https://stackoverflow.com/questions/21990892

  •  15-10-2022
  •  | 
  •  

Question

I have an entity which has a relation to itself (auto-join), implementing a typical hierarchical relation. It has an Id and a ParentId (both of type int). The Id is an identity field in the table, so its value is geenrated on saving, and this is correctly reflected in the EF model.

When I try to save a new entity (with Add + SaveChanges) with ParentId = 0, EF shows this error:

Unable to determine a valid ordering for dependent operations.

How can I avoid it?

Était-ce utile?

La solution

EF has an strange behaviour in this case: obviously, as it's a new entity, and the Id will be generated buythe db, it isn't initialized and has its default value of 0.

When EF tries to determine how to save this entity, it finds that its Id and its ParentId are equal (both are equal to zero). This makes EF find a circular reference of the entity with itself, and thus the error.

To solve the problem you simply have to break the circular reference. As the value of the Id will eventually be generated by the database, it doesn't matter which value it has when it's added to the context for saving. So, you simply have to give the Id a value other than zero, and it works like a charm.

In this partiuclar case, I'm handling legacy code, and this is the only solution. But, for a new application, see the recommendations below.

Avoiding this problem by design

The simplest solution for this problem, it's to avoid having an entity with Id = 0. In this way, there will be no accidental "circular reference".

If you see hvd's comments, you'll find that there is a second problem: you can't insert the first row using your EF code, because the Id and the ParentId would have to be the same, and, as stated, this will make EF fail. To solve this problem you have two options:

  1. Change the design so that ParentId can be null (make it int?). In this way, you can insert the first row with a null value in ParentId
  2. Execute a direct INSERT INTO sentence for the first insertion (in SSMS, using ADO.NET, executing the query directly from the context...). If you do so, the insertion will be handled directly by the DB, and there will be no problem.

NOTE 1: In both cases, inserting a row related to itself is impossible through EF.

NOTE 2: Depending on the number of rows in the table, making the parent id nullable can degrade query performance, and take up more disk space: an INT NOT NULL column takes up less space, and gives better performance on indexing than an INT NULL column. If this is a concern, take the 2nd solution.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top