Working with Cascade Delete in Entity Framework

Recently my group and I are working on a .NET Web API project. At some points after defining our design models, view models and the mappings, the Entity Framework didn’t create the local database for us.

When we enabled migrations and tried to run Update-Database on Package Manager Console, this error generated:

Screen Shot 2018-02-11 at 8.19.51 PM

It complains about the foreign key constraint on table Resident will cause cascade delete, which means if the table City got deleted, then the foreign key onΒ table Resident will set to null.

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.

If you take a look at the migration test file, which generated by theΒ Add-Migration Test command, you will notice when creating the foreign key “CityId” for table Resident, the cascade delete is turned on by default.

Screen Shot 2018-02-12 at 1.16.11 AM

In order to create our tables, we could configureΒ Fluent API to turn off the cascade delete. But first, let’s take a look at our design models:

City.cs


namespace CascadeDelete.Models
{
public class City
{
public City()
{
Owners = new List<ResidentCityOwn>();
Residents = new List<Resident>();
}
public int Id { get; set; }
[Required]
[StringLength(40)]
public string Name { get; set; }
// navigations
public virtual ICollection<ResidentCityOwn> Owners { get; set; }
public virtual ICollection<Resident> Residents { get; set; }
}
}

view raw

City.cs

hosted with ❤ by GitHub

ResidentCityOwn.cs


namespace CascadeDelete.Models
{
public class ResidentCityOwn
{
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Title { get; set; }
[Required]
public int ResidentId { get; set; }
[Required]
public int CityId { get; set; }
// navigation props
public virtual Resident Resident { get; set; }
public virtual City City { get; set; }
}
}

Resident.cs


namespace CascadeDelete.Models
{
public class Resident
{
public Resident()
{
ResidentCityOwns = new List<ResidentCityOwn>();
}
public int Id { get; set; }
public String Name { get; set; }
[Required]
public int CityId { get; set; }
// navigation props
public virtual City City { get; set; }
public virtual ICollection<ResidentCityOwn> ResidentCityOwns { get; set; }
}
}

view raw

Resident.cs

hosted with ❤ by GitHub

Because the error is pointing to the Resident class, so we just focus on City and Resident for now. Note the City has a collection of Residents, so they are one-to-many.

Now put the configuration in DataContext.cs:


namespace CascadeDelete.Models
{
public class DataContext: DbContext
{
public virtual DbSet<Resident> Residents { get; set; }
public virtual DbSet<City> Cities { get; set; }
public virtual DbSet<ResidentCityOwn> ResidentCityOwn { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Fluent API configurations
modelBuilder.Entity<Resident>()
.HasRequired(e => e.City)
.WithMany(e => e.Residents)
.WillCascadeOnDelete(false);
}
}
}

view raw

DataContext.cs

hosted with ❤ by GitHub

Delete the previous migration file and start over, now you should see the following:

Screen Shot 2018-02-12 at 1.13.38 AM

Run the Update-Database command, and the database file should be generated:

Screen Shot 2018-02-12 at 1.27.15 AM

Sum up:

You probably not see the cascade delete very often. But sometimes based on your business logic, you want to configure your models to get rid of this default behavior, remember Fluent API is your friendπŸ™ŒπŸ™Œ.