Alx
Alx

Reputation: 6285

Cascade delete all children using Entity Framework Core with One-to-Many and Many-To-Many relationships

I have following simplified schema for a .net core 2 with entity framework core solution:

           1+--------+1
    +-------+Blogs   +-------+
    |       +--------+       |
   *|                        |*
+--------+             +----------+
|Posts   |             |Tags      |
+--------+             +----------+
    |1                      1|
    |   *+-------------+*    |
    +----+PostTags    |------+
         +-------------+

With following models:

public class Blog
{
    public int Id { get; set; }

    public ICollection<Post> Posts { get; set; }
    public ICollection<Post> Tags { get; set; }    
}

public class Post
{
    public int Id { get; set; }

    public Blog Blog { get; set; }
    public ICollection<PostTag> PostTags { get; set; }    
}

public class Tag
{
    public int Id { get; set; }

    public Blog Blog { get; set; }
    public ICollection<PostTag> PostTags { get; set; }    
}

public class PostTag
{
    public int PostId { get; set; }
    public Post Post { get; set; }

    public int TagId { get; set; }
    public Tag Tag { get; set; }
}

And the corresponding DbContext:

public class DataDbContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<Tag> Tags { get; set; }
    public DbSet<PostTag> PostTags { get; set; }       
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<PostTag>()
        .HasKey(u => new { pt.TagId, pt.PostId });

    modelBuilder.Entity<PostTag>()
        .HasOne(pt => pt.Post)
        .WithMany(p => p.PostTags)
        .HasForeignKey(pt => pt.PostId)
        .OnDelete(DeleteBehavior.Cascade)
        .IsRequired();

    modelBuilder.Entity<PostTag>()
        .HasOne(pt => pt.Tag)
        .WithMany(t => t.PostTags)
        .HasForeignKey(pt => pt.TagId)
        .OnDelete(DeleteBehavior.Cascade)
        .IsRequired();
}

The cascade delete works, but leaves Tags with blog nulled. If I [Require] the blog in Tag, I receive a circular constraint error.

I think I just found the answer myself:

"In SQL Server, a table cannot appear more than one time in a list of all the cascading referential actions that are started by either a DELETE or an UPDATE statement. For example, the tree of cascading referential actions must only have one path to a particular table on the cascading referential actions tree

from weblogs.asp.net

Is there an elegant solution for this in EF Core to ensure all Tags and Posts get deleted as soon as a Blog is being deleted?

Upvotes: 3

Views: 4180

Answers (1)

David Browne - Microsoft
David Browne - Microsoft

Reputation: 89090

Is there an elegant solution for this in EF Core to ensure all Tags and Posts get deleted as soon as a Blog is being deleted?

Your two options are:

1) Have a Posts->PostTags cascade delete and Blogs-> BlogTags cascade delete, and delete all the Blog's posts first, then delete the blog.

2) Write an INSTEAD OF DELETE trigger on Blogs to delete the related Posts and BlogTags before deleting the Blog.

Upvotes: 2

Related Questions