I'm trying to understand why Entity Framework Core 2's ChangeTracker sets the state of deleted entities to 'modified' if the deletion is done by removing the entity from a list in another entity.
Consider this example:
Class1 List<Class2> MyListOfClass2Objects Class2
Both classes have their own
DbSet in EF's
DbContext. If I remove an object from the
MyListOfClass2Objects list and then call
DbContext.SaveChanges(), the state of the
Class2 object in
ChangeTracker is set to
EntityState.Modified, and not
EntityState.Deleted, which I would expect. If I delete the entity by calling
Set<T>.Remove() the state in the
EntityState.Deleted. In both cases however, the entity is removed from the database.
So, why does Entity Framework set different values in ChangeTracker depending on how you delete an entity even though it is really deleted in both cases?
Update: At the end (thanks to @Sebastian finding) it turns out to be a known issue with the current (at the time of writing) EF Core implementation, tracked originally by EF Core marks entities removed From child collections as modified #10093. The short explanation is:
because cascade deletes happens while SaveChanges is running which means in your code will not see this state as it looks at the state before SaveChanges has executed
Cascade delete happens as part of SaveChanges.
Fixup of non-deleted entities to no longer reference deleted entities happens after SaveChanges.
The currently associated action item is Allow delete fixup and cascade timing to be configured #10114, unfortunately in backlog, i.e. unknown if and when will be addressed.
Because when you remove an entity from the corresponding
DbSet, you are telling EF that you want to delete it. But when you remove it from the parent entity collection, if the relationship is optinal (as it seems to be in your case), EF treats that as attempt to disassociate the child from the parent (same as setting
null), hence it sets the FK and parent navgigation property to
null and marks the entity as
Modified. If you really want to delete it, you should use the first method.
All this is explained in the Removing relationships section of the documentation:
You can remove a relationship by setting a reference navigation to null, or removing the related entity from a collection navigation.
Removing a relationship can have side effects on the dependent entity, according to the cascade delete behavior configured in the relationship.
By default, for required relationships, a cascade delete behavior is configured and the child/dependent entity will be deleted from the database. For optional relationships, cascade delete is not configured by default, but the foreign key property will be set to null.