La introducción de una restricción de CLAVE EXTRANJERA puede provocar 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 Carta que contiene Lados (normalmente 2), y tanto las Cartas como los Lados tienen un Escenario. Estoy usando migraciones de EF Codefirst y las migraciones fallan con este error:
La introducción de la restricción FOREIGN KEY 'FK_dbo.Sides_dbo.Cards_CardId' en la tabla 'Sides' puede provocar ciclos o múltiples rutas en cascada. Especifique AL ELIMINAR SIN ACCIÓN o AL ACTUALIZAR SIN ACCIÓN, o modifique otras restricciones de CLAVE EXTRANJERA.
Aquí está mi entidad de tarjeta :
public class Card
{
public Card()
{
Sides = new Collection<Side>();
Stage = Stage.ONE;
}
[Key]
[Required]
public virtual int CardId { get; set; }
[Required]
public virtual Stage Stage { get; set; }
[Required]
[ForeignKey("CardId")]
public virtual ICollection<Side> Sides { get; set; }
}
Aquí está mi entidad secundaria :
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<Stage> 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 correctamente. Si abro SSMS y miro las tablas, puedo ver que Stage_StageId
se ha agregado Cards
(como se esperaba/desear), sin embargo, Sides
no contiene ninguna referencia Stage
(no esperado).
Si luego agrego
[Required]
[ForeignKey("StageId")]
public virtual Stage Stage { get; set; }
public int StageId { get; set; }
En mi clase secundaria, veo StageId
una columna agregada a mi Side
tabla.
Esto está funcionando, pero ahora en toda mi solicitud, cualquier referencia a Stage
contiene un SideId
, que en algunos casos es totalmente irrelevante. Me gustaría simplemente darle a mis entidades Card
y una propiedad basada en la clase Stage anterior sin contaminar la clase stage con propiedades de referencia si es posibleSide
Stage
... ¿qué estoy haciendo mal?
Debido Stage
a que es obligatorio , todas las relaciones de uno a muchos Stage
involucradas tendrán la eliminación en cascada habilitada de forma predeterminada. Es decir, si eliminas una Stage
entidad
- la eliminación se realizará en cascada directamente a
Side
- la eliminación se realizará en cascada directamente hacia
Card
y porqueCard
ySide
tendrá una relación requerida de uno a muchos con la eliminación en cascada habilitada de nuevo de forma predeterminada, luego se realizará en cascada deCard
aSide
Por lo tanto, tiene dos rutas de eliminación en cascada desde Stage
hasta Side
, lo que provoca la excepción.
Debe hacer que sea Stage
opcional en al menos una de las entidades (es decir, eliminar el [Required]
atributo de las Stage
propiedades) o desactivar la eliminación en cascada con Fluent API (no es posible con anotaciones de datos):
modelBuilder.Entity<Card>()
.HasRequired(c => c.Stage)
.WithMany()
.WillCascadeOnDelete(false);
modelBuilder.Entity<Side>()
.HasRequired(s => s.Stage)
.WithMany()
.WillCascadeOnDelete(false);
Tenía una tabla que tenía una relación circular con otras y recibía el mismo error. Resulta que se trata de la clave externa que no admite valores NULL. Si la clave no admite valores NULL, el objeto relacionado debe eliminarse y las relaciones circulares no lo permiten. Así que utilice una clave externa que acepte valores NULL.
[ForeignKey("StageId")]
public virtual Stage Stage { get; set; }
public int? StageId { get; set; }