Entity Framework (EF) Code First Cascade Delete for One-to-Zero-or-One relationship

C#Entity FrameworkEf Code-FirstEntity Framework-5Cascading Deletes

C# Problem Overview


Following the "Code First Modeling" section of the Pluralsight "Getting Started with Entity Framework 5" course by Julie Lerman, I created two POCO classes with a one-to-zero-or-one relationship: a parent (User) and an optional child (UserDetail).

User and UserDetail data model diagram (click to view).

Notice in the diagram that the UserId property is a primary key and a foreign key for UserDetail.

Relevant code:

public class User
{
    //...
    
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    
    /* Has a 1:0..1 relationship with UserDetail */
    public virtual UserDetail UserDetail { get; set; }

    //...
}

public class UserDetail
{
    //...
    
    /* Has a 0..1:1 relationship with User */
    public virtual User User { get; set; }

    [Key, ForeignKey("User")]
    public int UserId { get; set; }
    
    //...
}

public class EFDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    //public DbSet<UserDetail> UserDetails { get; set; }  /* Explicit declaration not necessary. Context is aware of UserDetail entity due to 0..1:1 relationship with User */

    public EFDbContext()
    {
        Configuration.ProxyCreationEnabled = true;
        Configuration.LazyLoadingEnabled = true;
    }
}

public class UserRepository : IUserRepository
{
    private EFDbContext _context = new EFDbContext();

    public void Delete(User entity)
    {
        entity = _context.Users.Find(entity.UserId);

        //...

        _context.Users.Remove(entity);
        _context.SaveChanges();

        //...
    }
}

When the Delete() method in the UserRepository class is called, it does not delete the User record in the database because the foreign key in UserDetail does not have cascade delete enabled.

> The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.UserDetail_dbo.User_UserId".

How would you enable cascading deletes for one-to-zero-or-one relationships using Entity Framework Code First (so that deleting a User automatically deletes UserDetail)?

C# Solutions


Solution 1 - C#

You will have to use the fluent API to do this.

Try adding the following to your DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{   
    modelBuilder.Entity<User>()
        .HasOptional(a => a.UserDetail)
        .WithOptionalDependent()
        .WillCascadeOnDelete(true);
}

Solution 2 - C#

You could also disable the cascade delete convention in global scope of your application by doing this:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>()
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>()

Solution 3 - C#

This code worked for me

protected override void OnModelCreating(DbModelBuilder modelBuilder)
	{
		modelBuilder.Entity<UserDetail>()
			.HasRequired(d => d.User)
			.WithOptional(u => u.UserDetail)
			.WillCascadeOnDelete(true);
	}

The migration code was:

public override void Up()
    {
        AddForeignKey("UserDetail", "UserId", "User", "UserId", cascadeDelete: true);
    }

And it worked fine. When I first used

modelBuilder.Entity<User>()
    .HasOptional(a => a.UserDetail)
    .WithOptionalDependent()
    .WillCascadeOnDelete(true);

The migration code was:

AddForeignKey("User", "UserDetail_UserId", "UserDetail", "UserId", cascadeDelete: true); 

but it does not match any of the two overloads available (in EntityFramework 6)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionarsenalogyView Question on Stackoverflow
Solution 1 - C#hutchonoidView Answer on Stackoverflow
Solution 2 - C#rajeemcariazoView Answer on Stackoverflow
Solution 3 - C#LupaView Answer on Stackoverflow