Как отключить каскадное удаление для таблиц ссылок в коде EF-first?


сначала я хочу отключить каскадное удаление для таблицы ссылок с кодом Entity framework. Например, если у многих пользователей есть много ролей, и я пытаюсь удалить роль, я хочу, чтобы это удаление было заблокировано если в настоящее время нет пользователей, связанных с этой ролью. Я уже удаляю соглашение о каскадном удалении в моем OnModelCreating:

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

и затем я настроил таблицу ссылок на роль пользователя:

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

но когда EF создает базу данных, он создает удаление каскад для отношений внешнего ключа, например.

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

как я могу остановить EF, генерирующий этот каскад удаления?

3 58

3 ответа:

Я получил ответ. :- ) Эти каскадные удаления были созданы из-за ManyToManyCascadeDeleteConvention. Вам нужно удалить это соглашение, чтобы предотвратить его создание каскадных удалений для таблиц ссылок:

modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

Я согласен с Эбрамом Халилом, что выключение его для одного стола является хорошим вариантом. Однако мне нравится придерживаться как можно ближе к автоматически построенным миграциям, поэтому я бы настроил его в 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);

Я считаю, что это сохраняет удаление, идущее в другом направлении, поэтому, если оба должны быть заблокированы (имеет смысл в этом примере), аналогичный вызов должен быть сделан, начиная с Entity<User>(Role)

конечно, это происходит через века после того, как вопрос был спросил. Так что, возможно, он не был действителен в 2012 году.

Я считаю, что отключение ManyToManyCascadeDeleteConvention глобально это не мудрый вариант. Вместо этого, лучше отключить его только для заинтересованных таблица.

Это может быть достигнуто путем редактирования созданного файла миграции, для свойства cascadeDelete. Например:

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