c# - mvc - ¿Cómo deshabilitar la eliminación en cascada para las tablas de enlaces en el código EF primero?
entity framework database first español (3)
Quiero deshabilitar las eliminaciones en cascada para una tabla de enlaces con el código de entidad primero. Por ejemplo, si muchos usuarios tienen muchos roles e intento eliminar un rol, quiero que esa eliminación se bloquee a menos que no haya usuarios actualmente asociados con ese rol. Ya OnModelCreating
convención de eliminación en cascada en mi OnModelCreating
:
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
...
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
Y luego configuré la tabla de enlace de rol de usuario:
modelBuilder.Entity<User>()
.HasMany(usr => usr.Roles)
.WithMany(role => role.Users)
.Map(m => {
m.ToTable("UsersRoles");
m.MapLeftKey("UserId");
m.MapRightKey("RoleId");
});
Sin embargo, cuando EF crea la base de datos, crea una cascada de eliminación para las relaciones de clave externa, por ej.
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
¿Cómo puedo evitar que EF genere esta cascada de eliminación?
Creo que desactivar ManyToManyCascadeDeleteConvention
globalmente no es una buena opción. En cambio, es mejor desactivarlo solo para la tabla correspondiente .
Esto se puede lograr editando el archivo de migración generado, para la propiedad cascadeDelete
. Por ejemplo:
AddForeignKey("dbo.UsersRoles", "UserId", "dbo.User", "UserId", cascadeDelete: false);
Estoy de acuerdo con Ebram Khalil en que apagarla para una sola mesa es una buena opción. Sin embargo, me gusta mantenerme lo más cerca posible de las migraciones construidas automáticamente, así que lo configuré en 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);
Creo que esto conserva la eliminación yendo en la otra dirección, por lo que si ambos necesitan ser bloqueados (tiene sentido en este ejemplo) una llamada similar tendría que hacerse a partir de Entity<User>(Role)
Por supuesto, esto viene años después de que se hizo la pregunta. Por lo tanto, puede no haber sido válido en 2012.
Tengo la respuesta. :-) Esas eliminaciones en cascada se estaban creando debido a ManyToManyCascadeDeleteConvention
. Debe eliminar esta convención para evitar que cree eliminaciones en cascada para tablas de enlaces:
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();