Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework (Core) - cascading delete

I’m using EF Core 3.1.1, but I believe this question applies to all versions of EF.

It seems the EF has the ability to cascade delete - if it is enabled, and if the dependent objects are loaded in the context.

var blog = context.blogs.Include(x => x.Posts).First(x => x.BlogId == id);
context.blogs.Remove(blog);

The above statement deletes all the blog’s posts, and then the blog - each with a different sql statement.

This is what I want, however when using code-first, it also creates the tables with cascading delete enabled in the database. (ON DELETE CASCADE)

Can you enable cascade delete in EF, and rely of EF deleting dependent objects, without also enabling database level cascade delete? (Or am I understanding this incorrectly?)

The reason is migrations fail because SQL won’t enable cascade delete in the database because it detects multiple cascade paths (even though multiple wouldn’t occur naturally in the schema)

Thanks!

like image 561
J. Lee Avatar asked Feb 04 '23 16:02

J. Lee


2 Answers

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); 
like image 62
Ivan Stoev Avatar answered Feb 26 '23 19:02

Ivan Stoev


You can add the Cascade Behavior to your entities as below. inside OnModelCreating;

foreach (var foreignKey in builder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
            {
                foreignKey.DeleteBehavior = DeleteBehavior.Cascade;
            }

enter image description here

like image 40
Erdogan Avatar answered Feb 26 '23 21:02

Erdogan