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 ChangeTracker
is 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
and
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.
Original:
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 child.Parent
to 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.