Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deleted entities show up as modified in Entity Framework Core's ChangeTracker

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?

like image 521
SebastianR Avatar asked Mar 25 '18 18:03

SebastianR


People also ask

How do I use ChangeTracker in EF core?

See Change Detection and Notifications for more information on how EF Core automatically detects changes like this. Call ChangeTracker. HasChanges() to determine whether any changes have been made that will cause SaveChanges to make updates to the database. If HasChanges return false, then SaveChanges will be a no-op.

How do I clear tracked entities in Entity Framework?

You can just call context. Entry(entity). State = EntityState. Detached and it will stop tracking that particular entity.

How do I Soft delete in Entity Framework?

The Soft Delete feature allows you to flag entities as deleted (Soft Delete) instead of deleting them physically (Hard Delete). The soft delete feature can be achieved by using the 'IEFSoftDelete' interface. By default, this interface is always added to the manager.

How does Entity Framework keep track of changes?

The Change Tracking tracks changes while adding new record(s) to the entity collection, modifying or removing existing entities. Then all the changes are kept by the DbContext level. These track changes are lost if they are not saved before the DbContext object is destroyed.


1 Answers

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.

like image 116
Ivan Stoev Avatar answered Sep 29 '22 00:09

Ivan Stoev