web-dev-qa-db-fra.com

Comment désactiver la suppression en cascade pour les tables de liens dans le code EF en premier?

Je souhaite désactiver les suppressions en cascade pour une table de liens avec le code de structure d'entité en premier. Par exemple, si de nombreux utilisateurs ont plusieurs rôles et que j'essaie de supprimer un rôle, je souhaite que cette suppression soit bloquée à moins que aucun utilisateur n'est actuellement associé à ce rôle. J'ai déjà supprimé la convention de suppression en cascade dans mon OnModelCreating:

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

Et puis j'ai mis en place la table de lien de rôle utilisateur:

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

Pourtant, lorsque EF crée la base de données, il crée une cascade de suppression pour les relations de clé étrangère, par exemple.

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

Comment puis-je arrêter EF de générer cette cascade de suppression?

63
Jez

J'ai eu la réponse. :-) Ces suppressions en cascade étaient en cours de création à cause de ManyToManyCascadeDeleteConvention. Vous devez supprimer cette convention pour l'empêcher de créer des suppressions en cascade pour les tables de liens:

modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
104
Jez

Je suis d'accord avec Ebram Khalil que le désactiver pour une seule table est une bonne option. J'aime rester aussi proche que possible des migrations construites automatiquement, donc je le configurerais dans 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);

Je crois que cela préserve la suppression dans l'autre sens, donc si les deux devaient être bloqués (cela a du sens dans cet exemple), un appel similaire devrait être effectué en commençant par Entity<User>(Role)

Bien sûr, cela survient bien après que la question a été posée. Il n'est donc peut-être pas valable en 2012.

5
TwainJ

Je pense que désactiver ManyToManyCascadeDeleteConvention globalement n'est pas une option judicieuse. Au lieu de cela, il est préférable de le désactiver uniquement pour la table concernée .

Ceci peut être réalisé en modifiant le fichier de migration généré, pour la propriété cascadeDelete. Par exemple:

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

2
ebram khalil