Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EntityFramework: How to configure Cascade-Delete to nullify Foreign Keys

EntityFramework's documentation states that the following behavior is possible:

If a foreign key on the dependent entity is nullable, Code First does not set cascade delete on the relationship, and when the principal is deleted the foreign key will be set to null.

(from http://msdn.microsoft.com/en-us/jj591620)

However, I cannot achieve such a behavior.

I have the following Entities defined with code-first:

public class TestMaster {     public int Id { get; set; }     public string Name { get; set; }             public virtual ICollection<TestChild> Children { get; set; }        }  public class TestChild {     public int Id { get; set; }     public string Name { get; set; }     public virtual TestMaster Master { get; set; }     public int? MasterId { get; set; } } 

Here is the Fluent API mapping configuration:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)     {         modelBuilder.Entity<TestMaster>()                     .HasMany(e => e.Children)                     .WithOptional(p => p.Master).WillCascadeOnDelete(false);          modelBuilder.Entity<TestChild>()                     .HasOptional(e => e.Master)                     .WithMany(e => e.Children)                     .HasForeignKey(e => e.MasterId).WillCascadeOnDelete(false);     } 

Foreign Key is nullable, navigation property is mapped as Optional, so I expect the cascade delete to work as described as MSDN - i.e. to nullify MasterID's of all children and then delete the Master object.

But when I actually try to delete, I get the FK violation error:

 using (var dbContext = new TestContext())         {             var master = dbContext.Set<TestMaster>().Find(1);             dbContext.Set<TestMaster>().Remove(master);             dbContext.SaveChanges();         } 

On SaveChanges() it throws the following:

System.Data.Entity.Infrastructure.DbUpdateException : An error occurred while updating the entries. See the inner exception for details. ----> System.Data.UpdateException : An error occurred while updating the entries. See the inner exception for details. ----> System.Data.SqlClient.SqlException : The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.TestChilds_dbo.TestMasters_MasterId". The conflict occurred in database "SCM_Test", table "dbo.TestChilds", column 'MasterId'. The statement has been terminated. 

Am I doing something wrong or did I misunderstood what the MSDN says?

like image 797
Alex Avatar asked Mar 05 '13 14:03

Alex


People also ask

How do I set up delete cascade?

Use the ON DELETE CASCADE option to specify whether you want rows deleted in a child table when corresponding rows are deleted in the parent table. If you do not specify cascading deletes, the default behavior of the database server prevents you from deleting data in a table if other tables reference it.

How do I enable cascade delete in Entity Framework?

Cascade delete automatically deletes dependent records or sets null to ForeignKey columns when the parent record is deleted in the database. Cascade delete is enabled by default in Entity Framework for all types of relationships such as one-to-one, one-to-many and many-to-many.

What is Cascade delete in EF core?

Cascade delete allows the deletion of a row to trigger the deletion of related rows automatically. EF Core covers a closely related concept and implements several different delete behaviors and allows for the configuration of the delete behaviors of individual relationships.


1 Answers

It works indeed as described but the article on MSDN misses to emphasize that it only works if the children are loaded into the context as well, not only the parent entity. So, instead of using Find (which only loads the parent) you must use eager loading with Include (or any other way to load the children into the context):

using (var dbContext = new TestContext()) {     var master = dbContext.Set<TestMaster>().Include(m => m.Children)         .SingleOrDefault(m => m.Id == 1);     dbContext.Set<TestMaster>().Remove(master);     dbContext.SaveChanges(); } 

This will delete the master from the database, set all foreign keys in the Child entities to null and write UPDATE statements for the children to the database.

like image 125
Slauma Avatar answered Oct 13 '22 14:10

Slauma