410 Stimmen

Das Hinzufügen einer Fremdschlüssel-Einschränkung kann zu Zyklen oder mehrfachen Kaskadenpfaden führen - warum?

Ich habe eine Weile damit gerungen und kann nicht ganz herausfinden, was passiert. Ich habe eine Card-Entität, die Seiten (normalerweise 2) enthält - und sowohl Cards als auch Seiten haben eine Stage. Ich verwende EF Codefirst-Migrationen und die Migrationen schlagen mit diesem Fehler fehl:

Durch das Einführen des Fremdschlüsselconstraints 'FK_dbo.Sides_dbo.Cards_CardId' in der Tabelle 'Sides' können Zyklen oder mehrere Kaskadenpfade entstehen. Geben Sie ON DELETE NO ACTION oder ON UPDATE NO ACTION an oder ändern Sie andere Fremdschlüssel Constraints.

Hier ist meine Card-Entität:

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; }
}

Hier ist meine Side-Entität:

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; }

}

Und hier ist meine Stage-Entität:

public class Stage
{
    // Null
    public static readonly Stage ONE = new Stage(new TimeSpan(0, 0, 0), "ONE");
    // Zehn Sekunden
    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; } }
}

Was seltsam ist, ist dass, wenn ich Folgendes meiner Stage-Klasse hinzufüge:

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

Die Migration erfolgreich durchgeführt wird. Wenn ich SSMS öffne und mir die Tabellen anschaue, sehe ich, dass Stage_StageId zu Cards hinzugefügt wurde (wie erwartet/gewünscht), jedoch enthält Sides keine Referenz zu Stage (nicht erwartet).

Wenn ich dann hinzufüge

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

Zu meiner Side-Klasse, sehe ich, dass die StageId-Spalte zu meiner Side-Tabelle hinzugefügt wurde.

Dies funktioniert, aber jetzt enthält in meiner Anwendung jede Referenz zu Stage eine SideId, die in einigen Fällen völlig irrelevant ist. Ich möchte meinen Card- und Side-Entitäten einfach eine Stage-Eigenschaft basierend auf obiger Stage-Klasse geben, ohne die Stage-Klasse mit Referenzeigenschaften zu verschmutzen, wenn möglich... was mache ich falsch?

0voto

Der einfache Weg ist, Ihre Migrationsdatei (cascadeDelete: true) in (cascadeDelete: false) zu ändern, und dann den Befehl Update-Database in Ihrer Paket-Manager-Konsole zuzuweisen. Wenn es ein Problem mit Ihrer letzten Migration gibt, dann ist alles in Ordnung. Andernfalls überprüfen Sie Ihre frühere Migrationshistorie, kopieren Sie diese Dinge, fügen Sie sie in Ihre letzte Migrationsdatei ein und tun Sie dasselbe. Bei mir hat es perfekt funktioniert.

0voto

Ayson Baxter Punkte 499

Keine der oben genannten Lösungen hat für mich funktioniert. Was ich tun musste, war ein nullable int (int?) für den Fremdschlüssel zu verwenden, der nicht erforderlich war (oder kein not null Spalten-Schlüssel) und dann einige meiner Migrationen zu löschen.

Beginnen Sie damit, die Migrationen zu löschen, dann versuchen Sie das nullable int.

Das Problem war sowohl eine Änderung als auch ein Modellentwurf. Es war kein Codeänderung erforderlich.

0voto

FelixAVeras Punkte 704

Sie könnten dies in Ihrer DataContext.cs hinzufügen, das funktioniert für mich...

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

-3voto

Ich bin auf das gleiche Problem gestoßen und war lange Zeit stecken geblieben. Die folgenden Schritte haben mir geholfen. Gehe durch die Einschränkungen und ändere das onDelete ReferentialAction auf NoAction von Cascade

  constraints: table =>
  {
      table.PrimaryKey("PK_table1", x => x.Id);
      table.ForeignKey(
         name: "FK_table1_table2_table2Id",
         column: x => x.table2Id,
         principalTable: "table2",
         principalColumn: "Id",
         onDelete: ReferentialAction.NoAction);
  });

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X