La introducción de una restricción de CLAVE EXTRANJERA puede provocar ciclos o múltiples rutas en cascada: ¿por qué?

Resuelto SB2055 asked hace 11 años • 20 respuestas

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_StageIdse ha agregado Cards(como se esperaba/desear), sin embargo, Sidesno 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 StageIduna columna agregada a mi Sidetabla.

Esto está funcionando, pero ahora en toda mi solicitud, cualquier referencia a Stagecontiene un SideId, que en algunos casos es totalmente irrelevante. Me gustaría simplemente darle a mis entidades Cardy una propiedad basada en la clase Stage anterior sin contaminar la clase stage con propiedades de referencia si es posibleSideStage ... ¿qué estoy haciendo mal?

SB2055 avatar Jun 16 '13 02:06 SB2055
Aceptado

Debido Stagea que es obligatorio , todas las relaciones de uno a muchos Stageinvolucradas tendrán la eliminación en cascada habilitada de forma predeterminada. Es decir, si eliminas una Stageentidad

  • la eliminación se realizará en cascada directamente aSide
  • la eliminación se realizará en cascada directamente hacia Cardy porque Cardy Sidetendrá 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 de CardaSide

Por lo tanto, tiene dos rutas de eliminación en cascada desde Stagehasta Side, lo que provoca la excepción.

Debe hacer que sea Stageopcional en al menos una de las entidades (es decir, eliminar el [Required]atributo de las Stagepropiedades) 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);
Slauma avatar Jun 15 '2013 20:06 Slauma

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; }
Cem Mutlu avatar Jul 03 '2015 15:07 Cem Mutlu