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:
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.
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; } | |
} | |
} |
ResidentCityOwn.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; } | |
} | |
} |
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
Delete the previous migration file and start over, now you should see the following:
Run the Update-Database
command, and the database file should be generated:
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ππ.