1. ホーム
  2. .net

[解決済み] FOREIGN KEY制約を導入すると、サイクルや複数のカスケード・パスが発生する可能性があります - なぜですか?

2022-03-15 23:50:58

質問

しばらく悩んでいるのですが、何が起こっているのかよくわかりません。 私はSides(通常2)を含むCardエンティティを持っており、CardとSidesの両方がStageを持っています。 私はEF Codefirstの移行を使用していますが、移行はこのエラーで失敗しています。

のFOREIGN KEY制約 'FK_dbo.Sides_dbo.Cards_CardId' を導入しています。 テーブル 'Sides' にサイクルが発生したり、複数のカスケード・パスが発生したりする可能性があります。ONを指定します。 DELETE NO ACTION または ON UPDATE NO ACTION、あるいは他の FOREIGN KEY を変更する。 制約があります。

以下、私の カード の実体があります。

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

ここで、私の 側面 の実体があります。

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

}

そして、これが私の ステージ のエンティティを使用します。

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

変なのは、Stageクラスに以下を追加した場合です。

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

移行は正常に実行されます。 SSMSを開いてテーブルを見ると Stage_StageId に追加されました。 Cards (予想通り/希望通り) しかし Sides への参照は含まれていません。 Stage (予想外)です。

次に

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

私のSideクラスには StageId カラムが追加され、私の Side テーブルを作成します。

これは動作していますが、現在、私のアプリケーション全体を通して、すべての Stage には SideId のように、場合によっては全く関係ないこともあります。 ただ、私の CardSide のエンティティは Stage のプロパティは、可能であれば参照プロパティでステージクラスを汚染することなく、上記のステージクラスに基づいて ... 私は何を間違えているのでしょうか?

どうすればいいですか?

なぜなら Stage 必須 の場合、すべての1対多の関係で Stage が関与している場合、デフォルトでカスケード削除が有効になります。つまり、もしあなたが Stage エンティティ

  • に直接カスケードされます。 Side
  • に直接カスケードされます。 Card であり Card そして Side は、デフォルトでカスケード削除が有効な1対多のリレーションシップが必要です。 Card から Side

という2つのカスケード削除パスがあるわけです。 Stage から Side - という例外が発生します。

にするか、あるいは Stage 少なくとも一つのエンティティでオプションとなります。 [Required] 属性は Stage プロパティ) を使用するか、Fluent API を使用してカスケード削除を無効にします (データアノテーションでは不可能)。

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

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