La introducción de la restricción FOREIGN KEY puede causar ciclos o múltiples rutas en cascada, ¿por qué?

He estado luchando con esto por un tiempo y no puedo entender qué está pasando. Tengo una entidad de tarjeta que contiene lados (generalmente 2), y ambas cartas y lados tienen un escenario. Estoy utilizando migraciones de EF Codefirst y las migraciones están fallando con este error:

La introducción de la restricción FOREIGN KEY ‘FK_dbo.Sides_dbo.Cards_CardId’ en la tabla ‘Laterales’ puede provocar ciclos o múltiples trayectos en cascada. Especifique ON DELETE NO ACTION o ON UPDATE NO ACTION, o modifique otras restricciones FOREIGN KEY.

Aquí está mi entidad de tarjeta :

public class Card { public Card() { Sides = new Collection(); Stage = Stage.ONE; } [Key] [Required] public virtual int CardId { get; set; } [Required] public virtual Stage Stage { get; set; } [Required] [ForeignKey("CardId")] public virtual ICollection Sides { get; set; } } 

Aquí está mi entidad lateral :

 public class Side { public Side() { Stage = Stage.ONE; } [Key] [Required] public virtual int SideId { get; set; } [Required] public virtual Stage Stage { get; set; } [Required] public int CardId { get; set; } [ForeignKey("CardId")] public virtual Card Card { get; set; } } 

Y aquí está mi entidad Stage :

 public class Stage { // Zero public static readonly Stage ONE = new Stage(new TimeSpan(0, 0, 0), "ONE"); // Ten seconds public static readonly Stage TWO = new Stage(new TimeSpan(0, 0, 10), "TWO"); public static IEnumerable Values { get { yield return ONE; yield return TWO; } } public int StageId { get; set; } private readonly TimeSpan span; public string Title { get; set; } Stage(TimeSpan span, string title) { this.span = span; this.Title = title; } public TimeSpan Span { get { return span; } } } 

Lo extraño es que si agrego lo siguiente a mi clase Stage:

  public int? SideId { get; set; } [ForeignKey("SideId")] public virtual Side Side { get; set; } 

La migración se ejecuta con éxito. Si abro SSMS y miro las tablas, puedo ver que Stage_StageId se ha agregado a Cards (como se esperaba / se desea), sin embargo, Sides no contiene referencia a Stage (no esperado).

Si luego agrego

  [Required] [ForeignKey("StageId")] public virtual Stage Stage { get; set; } public int StageId { get; set; } 

Para mi clase Side, veo la columna StageId agregada a mi Side Table.

Esto funciona, pero ahora, a lo largo de mi aplicación, cualquier referencia a Stage contiene un SideId , que en algunos casos es totalmente irrelevante. Me gustaría dar a mis Card y entidades Side una propiedad de Stage basada en la clase de escenario anterior sin contaminar la clase de escenario con propiedades de referencia si es posible … ¿qué estoy haciendo mal?

Como se requiere Stage , todas las relaciones uno a muchos en las que Stage esté involucrado tendrán habilitada la eliminación en cascada de forma predeterminada. Significa, si borras una entidad Stage

  • la eliminación irá en cascada directamente a Side
  • la eliminación se insertará en cascada directamente en la Card y dado que Card y Side tienen una relación de uno a varios requerida con la eliminación en cascada activada de forma predeterminada, volverá a conectarse en cascada de la Card al Side

Por lo tanto, tiene dos rutas de eliminación en cascada de Stage a Side , lo que causa la excepción.

Debe hacer que el Stage opcional en al menos una de las entidades (es decir, eliminar el atributo [Required] de las propiedades del Stage ) o deshabilitar la eliminación en cascada con la API Fluent (no es posible con las anotaciones de datos):

 modelBuilder.Entity() .HasRequired(c => c.Stage) .WithMany() .WillCascadeOnDelete(false); modelBuilder.Entity() .HasRequired(s => s.Stage) .WithMany() .WillCascadeOnDelete(false); 

Tenía una mesa que tenía una relación circular con otras personas y recibía el mismo error. Resulta que se trata de la clave externa que no fue nulable. Si la clave no es anulable, el objeto relacionado debe ser eliminado y las relaciones circulares no lo permiten. Por lo tanto, use una clave externa anulable.

 [ForeignKey("StageId")] public virtual Stage Stage { get; set; } public int? StageId { get; set; } 

Recibí este error para muchas entidades cuando estaba migrando de un modelo EF7 a una versión EF6. No quería tener que pasar por cada entidad de a una por vez, así que utilicé:

 builder.Conventions.Remove(); builder.Conventions.Remove(); 

Cualquiera que se pregunte cómo hacerlo en el núcleo de EF:

  protected override void OnModelCreating(ModelBuilder modelBuilder) { foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys())) { relationship.DeleteBehavior = DeleteBehavior.Restrict; } ..... rest of the code..... 

Puede configurar cascadeDelete como falso o verdadero (en su método de migración Arriba). Depende de tu requerimiento

 AddForeignKey("dbo.Stories", "StatusId", "dbo.Status", "StatusID", cascadeDelete: false); 

También tuve este problema, lo resolví al instante con esta respuesta de un hilo similar

En mi caso, no quise eliminar el registro dependiente en la eliminación de teclas. Si este es el caso en su situación simplemente cambie el valor booleano en la migración a falso:

 AddForeignKey("dbo.Stories", "StatusId", "dbo.Status", "StatusID", cascadeDelete: false); 

Lo más probable es que, si está creando relaciones que generan este error de comstackción, pero NO desea mantener la eliminación en cascada; tienes un problema con tus relaciones.

Esto suena raro y no sé por qué, pero en mi caso eso estaba sucediendo porque mi ConnectionString estaba usando “.” en el atributo “fuente de datos”. Una vez que lo cambié a “localhost” funcionó como un amuleto. Ningún otro cambio fue necesario.

En .NET Core cambié la opción onDelete a ReferencialAction.NoAction

  constraints: table => { table.PrimaryKey("PK_Schedule", x => x.Id); table.ForeignKey( name: "FK_Schedule_Teams_HomeId", column: x => x.HomeId, principalTable: "Teams", principalColumn: "Id", onDelete: ReferentialAction.NoAction); table.ForeignKey( name: "FK_Schedule_Teams_VisitorId", column: x => x.VisitorId, principalTable: "Teams", principalColumn: "Id", onDelete: ReferentialAction.NoAction); }); 

Las respuestas existentes son geniales. Solo quería agregar que encontré este error por un motivo diferente. Quería crear una migración EF inicial en una base de datos existente, pero no utilicé la bandera -IgnoreChanges y apliqué el comando Actualizar base de datos en una base de datos vacía (también falla la existente).

En cambio, tuve que ejecutar este comando cuando la estructura de db actual es la actual:

 Add-Migration Initial -IgnoreChanges 

Es probable que haya un problema real en la estructura db, pero salve el mundo paso a paso …

Arreglé esto. Cuando agregue la migración, en el método Up () habrá una línea como esta:

.ForeignKey (“dbo.Members”, t => t.MemberId, cascadeDelete: True)

Si borraste la cascadaDelete del final, funcionará.

Solo para fines de documentación, para alguien que viene en el futuro, esto se puede resolver tan simple como esto, y con este método, podría hacer un método que se deshabilitara una vez, y usted podría acceder a su método normalmente

Agregue este método a la clase de base de datos de contexto:

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove(); } 

En .NET Core , jugué con todas las respuestas superiores, pero sin éxito. Realicé muchos cambios en la estructura de la base de datos y cada vez añadí una nueva migración intentando update-database , pero recibí el mismo error.

Luego comencé a remove-migration una por una hasta que la consola de Package Manager me lanzó una excepción:

La migración ‘20170827183131 _ ***’ ya se ha aplicado a la base de datos

Después de eso, agregué nuevas migraciones ( add-migration ) y update-database éxito

Así que mi sugerencia sería: borrar todas sus migraciones temporales, hasta su estado actual de base de datos.

Ninguna de las soluciones antes mencionadas funcionó para mí. Lo que tenía que hacer era utilizar un int (int) nullable en la clave foránea que no era necesaria (o no una clave de columna nula) y luego eliminar algunas de mis migraciones.

Comience por eliminar las migraciones, luego pruebe la int nullable.

El problema fue tanto una modificación como un diseño de modelo. No fue necesario cambiar el código.