Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable cascade delete for link tables in EF code-first?

I want to disable cascade deletes for a link table with entity framework code-first. For example, if many users have many roles, and I try to delete a role, I want that delete to be blocked unless there are no users currently associated with that role. I already remove the cascade delete convention in my OnModelCreating:

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
    ...
    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

And then I set up the user-role link table:

modelBuilder.Entity<User>()
    .HasMany(usr => usr.Roles)
    .WithMany(role => role.Users)
    .Map(m => {
        m.ToTable("UsersRoles");
        m.MapLeftKey("UserId");
        m.MapRightKey("RoleId");
    });

Yet when EF creates the database, it creates a delete cascade for the foreign key relationships, eg.

ALTER TABLE [dbo].[UsersRoles]  WITH CHECK ADD  CONSTRAINT [FK_dbo.UsersRoles_dbo.User_UserId] FOREIGN KEY([UserId])
REFERENCES [dbo].[User] ([UserId])
ON DELETE CASCADE
GO

ALTER TABLE [dbo].[UsersRoles]  WITH CHECK ADD  CONSTRAINT [FK_dbo.UsersRoles_dbo.Role_RoleId] FOREIGN KEY([RoleId])
REFERENCES [dbo].[Role] ([RoleId])
ON DELETE CASCADE
GO

How can I stop EF generating this delete cascade?

like image 556
Jez Avatar asked Dec 04 '12 14:12

Jez


People also ask

How do I enable cascade delete in Entity Framework?

Cascade delete automatically deletes dependent records or sets null to ForeignKey columns when the parent record is deleted in the database. 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.

How do I prevent cascade delete in Salesforce?

To prevent records from being accidentally deleted, cascade-delete is disabled by default. Contact Salesforce Support to get the "Enables cascade delete on custom lookup relationships" feature enabled for your organization.

What is Cascade delete in EF core?

Cascade delete allows the deletion of a row to trigger the deletion of related rows automatically. EF Core covers a closely related concept and implements several different delete behaviors and allows for the configuration of the delete behaviors of individual relationships.


4 Answers

I got the answer. :-) Those cascade deletes were being created because of ManyToManyCascadeDeleteConvention. You need to remove this convention to prevent it from creating cascade deletes for link tables:

modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
like image 173
Jez Avatar answered Oct 02 '22 03:10

Jez


I believe that turning off ManyToManyCascadeDeleteConvention globally is not a wise option. Instead, it's better to turn it off only for the concerned table.

This can be achieved through editing the generated migration file, for property cascadeDelete. For example:

AddForeignKey("dbo.UsersRoles", "UserId", "dbo.User", "UserId", cascadeDelete: false);

like image 37
ebram khalil Avatar answered Oct 01 '22 03:10

ebram khalil


I agree with Ebram Khalil that turning it off for a single table is a good option. I like to stick as close to the automatically built migrations as I can, however, so I would set it up in OnModelCreating:

modelBuilder.Entity<User>()
    .HasMany(usr => usr.Roles)
    .WithMany(role => role.Users)
    .Map(m => {
        m.ToTable("UsersRoles");
        m.MapLeftKey("UserId");
        m.MapRightKey("RoleId");
    })
    .WillCascadeOnDelete(false);

I believe this preserves the delete going the other direction, so if both needed to be blocked (makes sense in this example) a similar call would need to be made starting with Entity<User>(Role)

Of course, this comes ages after the question was asked. So it may not have been valid in 2012.

like image 39
TwainJ Avatar answered Oct 05 '22 03:10

TwainJ


This works for me in EFCore 6.0.1 and MySql, according to ms docs.

Note: Don't forget to regenerate your migration files after this.

// In your dbContext class
protected override void OnModelCreating(ModelBuilder modelBuilder)
{    
     modelBuilder
          .Entity<User>()
          .HasMany(usr => usr.Roles)
          .WithMany(role => role.Users)
          .OnDelete(DeleteBehavior.Restrict);
}
like image 42
Victor SDK Avatar answered Oct 05 '22 03:10

Victor SDK