Deleting an Entity with related data and Cascading Deletes defined in SQLServer - entity-framework

I'm getting the following error when I SaveChanges after Removing an entity that has related entities containing data in the context as well. (The entity I'm deleting has the unique Primary Key). I have Cascading Delete configured at the SQL Server database level for the relation between the primary key table and the foreign key table.
"The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not su...
The primary entity has its related data loaded explicitly prior to me removing the primary from the context. I assumed that EF and SQL Server would take care of the cascaded delete for me. If the related entity has no data the delete (of the primary entity) works fine. If there is data in the related entity, I get the error above.
Any suggestions?

The lesson is that EF has a learning curve. Keep exploring.
Anyway, I was "deleting" entities by setting the state to "Deleted" then calling SaveChanges. This seems to work fine if the entity has no related data. However, if you have an entity that has related "child" entities, you need to call Remove on the parent entity for the "delete" to cascade through the graph. Live and learn. I'm pretty sure this is the answer. I think for the time being I'm going to stop setting State for deletes and use Remove instead.

Related

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?
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.

Which relationship prevents a delete?

When deleting an entity, I get the following error message:
The operation failed: The relationship could not be changed because
one or more of the foreign-key properties is non-nullable. When a
change is made to a relationship, the related foreign-key property is
set to a null value. If the foreign-key does not support null values,
a new relationship must be defined, the foreign-key property must be
assigned another non-null value, or the unrelated object must be
deleted.
Fair enough. However, I have many many relationships and I don't know which one causes the error.
Is there a way to get the name of the relationship that causes the problem?
Is there a way to get the name of the relationship that causes the problem?
Unfortunately no without quite complex exploration of ObjectStateManager. This is quite annoying problem because the exception is too generic without any additional information. I think it is a nice request for improvement and with EF as and open source it should really be possible to improve the quality of the exception.
You will have to go through your modification code and check entities you are trying to delete. There will be some related dependent entity which is not deleted and hangs the deletion of the parent entity. Other approach recommended for EF is to use cascade deletes.

Entity Framework 4.1 To know the which Foreign Key constraint is violated during deletion

I have started using Entity Framework 4.1 with Code first. I really love this over the previous ado.net techniques.
I have a very simple situation in which there is a department table and an employee table in database. Each employee belongs to a department and a department has got many employees. The business rule is : While, deleting a department, if there are any associated employees, it should not allow deletion. I can write a small method just before deletion and check the dependancy. However, since my project is a much complex one with more than 300 db tables, I hate to do this. The relationships gets changed frequently which results in lot of changes in all the delete methods of the project.
In ado.net, in similar situations, I used to parse the exception thrown and get the name of the particular Foreign key constraint which was violated. Based on the name of the violated FK constraint, I used to give appropriate error message to client. This technique worked well even in a fairly large project with more than 150 tables.
How do I do a similar thing in EF ? How do I get which FK is violated when SaveChanges() is called ?
You need to get the Message of the inner most exception(usually its a SqlException). Then you can extract the FK name from that string and check which FK is violated.

DbContext's ChangeTracker problem

I have a codefirst EF-4.1 based program. The user gets a context and can modify some properties. When the user is done, I do a quick
ChangeTracker.Entries().Any(e => e.State != EntityState.Unchanged);
to determine if a SaveChanges() is required or not. If I do a 'SaveChanges()' call, the changes that have made are persisted to the database.
This works for some properties, and doesn't work for others. Specifically it seems to work with simple types (floats), and with collection hierarchies(ObservableCollections).
Am I doing something wrong?
Yes this is a problem. Some relations are not tracked by DbChangeTracker. There is difference between Independent association and Foreign key association. Changes to relation are tracked in case of:
One-to-one relation which is always Foreign key association in EFv4+
One-to-many relation with Foreign key association - you should set up foreign key property
Changes to relation are not tracked in case of:
One-to-many relation with Independent association
Many-to-many relation which is always Independent association
Not tracked for Independent association is not correct naming. These changes are tracked but DbChangeTracker does not expose access to these changes! You must convert DbContext to ObjectContext and use ObjectStateManager to get access to ObjectStateEntries representing independent associations.
In this case the easiest thing is simply call SaveChanges always. It will not execute any DB commands if no data need to be saved.

Need to get to the foreign keys of an entity marked as "Deleted" for auditing

I'm using v1 of EF(.NET 3.5 SP1). I'm subscribing to the SavingChanges event of the ObjectContext wherein I audit deletes for a particular entity type. I need to get to the foreign keys of the entity being deleted i.e EntityKeys of the related entities (RelatedEnds) but the EntityKeys of the related entities are nulls.
Is there any way to get to the foreign keys of an entity which has been marked for deletion?
Does EF null out the EntityKeys of all RelatedEnds for an entity which has been marked for deletion? If so, is there a way I can get hold of the foreign keys?
I finally found an answer on the MSDN forums.
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/e4c4739f-731a-491a-a4c9-eb3c91f7c7eb