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


Answers

私は他の人と循環的な関係を持っていたテーブルを持っていて、同じエラーが発生していました。 それはヌル可能ではなかった外来キーに関するものです。 keyがnullでない場合、関連するオブジェクトは削除されなければならず、循環関係は許されません。 したがって、NULL可能な外部キーを使用してください。

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

私はしばらくこのことに取り組んできましたが、何が起きているのかは分かりません。 私はサイド(通常は2)を含むCardエンティティを持っています。また、カードとサイドの両方にステージがあります。 私はEF Codefirstの移行を使用しており、移行はこのエラーで失敗しています:

FOREIGN KEY制約 'FK_dbo.Sides_dbo.Cards_CardId'を 'Sides'テーブルに導入すると、サイクルまたは複数のカスケードパスが発生する可能性があります。 NO DELETE NO ACTIONまたはUP UP NO 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_StageIdCards追加されていることがStage_StageIdます(ただし、期待通りではありません)。

次に、

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

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

これはSideId 、私のアプリケーション全体を通して、 Stageへの参照にはSideIdが含まれていますSideIdは場合によっては完全に無関係です。 可能であれば、Stageクラスを参照プロパティで汚染せずに、私のCardおよびSideエンティティに上記のStageクラスに基づくStageプロパティを与えるだけです...私は何を間違っていますか?




.NETコアでは、私はすべての上位の回答と一緒にプレイしましたが、成功することはありませんでした。 私はDB構造で多くの変更を行いましたが、毎回update-databaseupdate-databaseしようとする新しい移行が追加されましたが、同じエラーが発生しました。

それから、 パッケージマネージャコンソールが私に例外を投げかけるまで、 remove-migration一つずつremove-migration始めました。

移行 '20170827183131 _ ***'は既にデータベースに適用されています

その後、新しいマイグレーション(マイグレーションのadd-migration )とupdate-database

だから私の提案は、あなたの現在のDB状態まで、すべての一時的移行をクリアすることです。




既存の回答は素晴らしいです。別の理由でこのエラーに遭遇したと付け加えたいだけです。 私は、既存のDB上でInitial EFの移行を作成したかったのですが、 -IgnoreChangesフラグを使用せず、空のデータベースに対してUpdate-Databaseコマンドを適用しました(既存の失敗も)。

代わりに、私は現在のdb構造が現在のものであるときにこのコマンドを実行しなければなりません:

Add-Migration Initial -IgnoreChanges

db構造には本当の問題があるかもしれないが、一度に世界を一歩救う...




前述の解決策のどれも私にとっては役に立たなかった。 私がしなければならなかったのは、不要な(またはヌルの列キーではない)外部キーに対してnull可能なint(int?)を使用してから、マイグレーションの一部を削除することでした。

まずマイグレーションを削除してから、ヌル可能なintを試してください。

問題は修正とモデル設計の両方でした。 コードを変更する必要はありませんでした。




私もこの問題を抱えていましたが、私は似たようなスレッドからこの答えを出して即座に解決しました

私の場合、私はキーの削除に関する従属レコードを削除したくなかった。 このような場合は、移行のブール値をfalseに変更するだけです。

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

あなたはこのコンパイラエラーをスローする関係を作成しているが、カスケード削除を維持したいと思う可能性があります。 あなたの関係に問題があります。




誰でも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.....