Cascade Deleting with Ef Core

Cascade deleting with EF Core

Cascade delete always works in one direction - from principal entity to dependent entity, i.e. deleting the principal entity deletes the dependent entities. And for one-to- many relationships the one side is always the principal and the many side is the dependent.

Looks like you are confused by the fluent configuration. Note that each relationship consists of two ends. The fluent configuration allows you to start with one of the ends and relate it to the other end, or vice versa, but still you are configuring (defining) a single relationship. So

Entity<A>().HasOne(a => a.B).WithMany(b => b.As)

is the same as

Entity<B>().HasMany(b => b.As).WithOne(a => a.B);

and they both define one and the same relationship. Which one you choose doesn't matter, just use single configuration per relationship in order to avoid discrepancies.

With that being said,

model.Entity<Post>().HasOne(p => p.Blog).WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogId)
.OnDelete(DeleteBehavior.Cascade);

and

model.Entity<Blog>().HasMany(b => b.Posts).WithOne(p => p.Blog)
.HasForeignKey(p => p.BlogId)
.OnDelete(DeleteBehavior.Cascade);

is one and the same and define single one-to-many relationship from Blog to Post. Since Blog is the one side and Post is the many side, the Blog is the principal entity and the Post is the dependent entity, hence deleting a Blog will delete the related Posts.

Reference:

  • Relationships - Definition of terms
  • Cascade Delete

Entity Framework (Core) - cascading delete

Actually EF Core 3.0 is the first version of EF which adds such capability via DeleteBehavior.ClientCascade option (unfortunately not yet included in the Cascade Delete section of the documentation):

For entities being tracked by the DbContext, dependent entities will deleted when the related principal is deleted.

If the database has been created from the model using Entity Framework Migrations or the EnsureCreated() method, then the behavior in the database is to generate an error if a foreign key constraint is violated.

Shortly, all Client* delete behaviors are mapped to Restrict, i.e. enforced FK relationship in database without cascade. Client behavior apply only on entities tracked by the context, so make sure you Include the related data before deleting (as in your sample).

To configure the option, you'd need fluent API at minimum having valid Has + With in order to get to OnDelete method, e.g.

modelBuilder.Entity<Blog>()
.HasMany(e => e.Posts)
.WithOne(e => e.Blog)
.OnDelete(DeleteBehavior.ClientCascade);

In EF Core Migration when setting Cascade Delete does it not enforce it in the database?

After looking through the project which I was trying to do this in a realised that the Dbcontext was inherited from a base class which had this code in...

private void ConfigureEntities(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly);

var entityTypes = modelBuilder.Model
.GetEntityTypes()
.ToList();

// Disable cascade delete
var foreignKeys = entityTypes
.SelectMany(e => e.GetForeignKeys().Where(f => f.DeleteBehavior == DeleteBehavior.Cascade));
foreach (var foreignKey in foreignKeys)
{
foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
}
}

In the end I copied this into the Gist Project and replicated it straight away.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(TestContext).Assembly);

var entityTypes = modelBuilder.Model
.GetEntityTypes()
.ToList();
var foreignKeys = entityTypes
.SelectMany(e => e.GetForeignKeys().Where(f => f.DeleteBehavior == DeleteBehavior.Cascade));
foreach (var foreignKey in foreignKeys)
{
foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
}

}

I'm not sure why this was done but plan to find out, I think it came from a previous Template that we were using.

EF Core Cascade Delete

This is what I ended up doing .. I did it in code

    public async Task DeleteRound(int Id)
{
var round = _context.Rounds.Where(e => e.Id==Id).Include(e => e.Activitys).First();
_context.Rounds.Remove(round);
await _context.SaveChangesAsync();
}

I had to add the following to the Round Class:

   public IList<Activity> Activitys { get; } = new List<Activity>();

No further code required. No need to populate the list as above. It seems that EF is doing it seamlessly. No need to annotate the Migration files.

Entity Framework Core Cascade Delete Error

I think the behavior is correct since when the master table deletes a record it should delete its related records in the detail table. No point in keeping it. Data will be redundant. But in case if we want to make such a scenario, though we set CascadeDelete to Restrict within the migration.cs it will not work as expected. The following article will help with understanding the behaviours.

https://learn.microsoft.com/en-us/ef/core/saving/cascade-delete

Entity Framework Core cascade delete one to many relationship

Described "problem" is not related to Entity Framework - this is restriction of MS SQL Server itself. Table with several FKs may have only one of them with cascade delete.

So, as soon as you need both FKs to have cascade - you should implement such "cleanup" in your code. Set one (or both) FKs to DeleteBehavior.Restrict, and in your controller/service prior to removing Station manually find and delete all related RegulatorySchedule



Related Topics



Leave a reply



Submit