web-dev-qa-db-ja.com

Entity Framework ALTER TABLEステートメントがFOREIGN KEY制約と競合しました

Entity Framework、Code First Migrationでデータベースを更新すると、このエラーが発生します:

ALTER TABLEステートメントがFOREIGN KEY制約「FK_dbo.Clients_dbo.MedicalGroups_MedicalGroupId」と競合しました。データベース「hrbc」、テーブル「dbo.MedicalGroups」、列「Id」で競合が発生しました。

これは私のクラスです:

public partial class Client
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int? MedicalGroupId { get; set; }
    [ForeignKey("MedicalGroupId")]
    public virtual MedicalGroups MedicalGroup { get { return _MedicalGroup; } set { _MedicalGroup = value; } }
}

これが私の2番目のクラスです。

public partial class MedicalGroups
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
}

そして、これは私が適用しようとしている私の移行です:

public override void Up()
{
    AddForeignKey("dbo.Clients", "MedicalGroupId", "dbo.MedicalGroups", "Id");
    CreateIndex("dbo.Clients", "MedicalGroupId");
}
48
Zaid Iqbal

私は私の問題の解決策を得ました。問題は、クライアントテーブルにある「データ」です。クライアントテーブルには実際には存在しないmedicalgroupid値があるため、外部キー制約に関するエラーが発生します。

Update Client set MedicalGroupId = NULL
2
Zaid Iqbal

FK制約と競合する既存のデータがデータベースに存在しないことを確認して、作成を失敗させます。

95
Turnkey

@Coryは正しい解決策に近づいていたと思うので、時間をかけて調査する必要はありませんでした。

追加移行コードでは、おそらく移行が生成されました

public override void Up()
{
AddColumn("dbo.ClientContacts", "FamilialRelationshipId", c => c.Int(nullable: false));
CreateIndex("dbo.ClientContacts", "FamilialRelationshipId");
AddForeignKey("dbo.ClientContacts", "FamilialRelationshipId", "dbo.FamilialRelationships",        "FamilialRelationshipId");
}

Nullable:falseに注意してください。モデルにintではなくintのIDがある場合(nullable int)移行コードはnullableをfalseに設定します。モデルは、デフォルトで0に設定されたnull不可のintを使用していることを示しています。おそらく、値が0の外部キーアイテムはありません。

ここで、外部キーテーブルに存在するデフォルト値を作成するか、SQL Serverを使用して制約を作成する場合、チェックなしで制約を作成する必要があります。ただし、[DefaultValue(0)]属性を使用してプロパティを修飾しても、デフォルト値が指定されている場合、SQL Column Addのように既存のデータは変更されません。

モデルクラスを変更して、null許容のintを許可することをお勧めします。次に、シードメソッドで、データアノテーションの[DefaultValue]属性はデータを変更しないため、dbcontextに対して単純なメソッドを作成して、新しい列をデフォルト値で更新します。

Add-Migration/Update-Databaseで列と制約を作成します。次に、null不可のintを許可する場合はモデルを変更し、すべての行を外部キーの有効な値に変更したと仮定して、Add-Migration/Update-databaseを再度変更します。これにより、モデルの移行で切れ目のないチェーンが得られます。データモデルの変更のフローはそのままであるため、後でライブサイトに公開するときに役立ちます。

  • お役に立てれば。
30
RickIsWright

このエラーは、外部キー制約に違反していることを示しています。解決するには、いくつかの解決策があります

  1. データの修正-Clientsテーブルに、存在しないMedicalGroupIdを持つレコードがある場所MedicalGroupsテーブル内。クエリを作成して、MedicalGroupsテーブルに存在しないIDを見つけ、自分でデータを手動で修正します。
  2. 外部キー制約を削除する-外部キー制約を削除すると、このメッセージに悩まされることはありません。残念ながら、データベースはこの関係を強制しなくなり、将来この問題を悪化させる可能性があります。
  3. WITH NOCHECKを使用して制約を作成-WITH NOCHECKオプションを使用して外部キー制約を作成できます。このオプションは、既存のデータにこの制約を適用しないようにSQL Serverに指示します。 SQL Serverは、今後のINSERTS/UPDATES/DELETESでこの制約をチェックします。
11
Cory

テーブルが空ではないため、この問題が発生します。したがって、外部キーのようにアタッチせずに新しいフィールドを追加する必要があります。 public int?MedicalGroupId {get; set;}。そして、パッケージ管理コンソールでupdate-databaseコマンドを実行します。次に、このテーブル(クライアント)のフィールドに正しいデータを入力します(値はMedicalGroupsIdに存在します)。外部キーを作成する行を挿入します[ForeignKey( "MedicalGroupId")] public virtual MedicalGroups MedicalGroup {get {return _MedicalGroup;} set {_MedicalGroup = value;}}。最後に、update-databaseコマンドを実行します。大丈夫でしょう。

6
chekib

ここに着くかもしれない他の人にとっては、Code-First Entity Frameworkを使用していて、既存のデータを含むテーブルに新しい必要な列を追加しようとすると、本当に簡単な修正があります。

注:これを行う前に、既存のすべての行に対してこの新しい列に有効な値を追加する必要があることを知ってください。先に進む前に、既存の行に追加する値を検討してください。必要なルックアップテーブルに「無効」または「不明」を示す値を指定できます。

モデルで、?を追加して列をヌル可能に設定します。 intの後。モデルを保存してコンパイルします。 Update-Databaseを実行します。

例:

[ForeignKey("Title")]
public int? TitleId { get; set; }

Dbで、NULL値を有効なルックアップ値に置き換えてテーブルを更新します。私の場合、タイトルルックアップテーブルに「不明」を追加し、すべての行を一括編集してそのルックアップIDを参照しました。

モデルに戻り、「?」を削除しますそのため、列はNULL値を許可されなくなりました。モデルを保存してコンパイルし、Update-Databaseを実行します

これで準備完了です。

4
GrayDwarf

DefaultValueセットでもこの問題が発生しました。

「1つ以上のオブジェクトがこの列にアクセスするため、オブジェクトは列ALTER TABLE ALTER COLUMNに依存しています。」.

結局、AddForeignKey/DropForeignKeyを新しい移行に移動し、別のデータベース更新コマンドで実行しました(1つのコマンドで両方の移行を実行しないでください。

    public override void Up()
    {
        CreateTable(
            "dbo.DecisionAccesses",
            c => new
            {
                Id = c.Int(nullable: false),
                Name = c.String(nullable: false, maxLength: 50),
            })
            .PrimaryKey(t => t.Id);

        CreateTable(
            "dbo.DecisionPersonStatus",
            c => new
            {
                Id = c.Int(nullable: false),
                Name = c.String(nullable: false, maxLength: 50),
            })
            .PrimaryKey(t => t.Id);

        AddColumn("dbo.DecisionForm_DecisionFields", "DecisionAccessId", c => c.Int(nullable: false, defaultValue: (int)DecisionAccess.Creator));
        AddColumn("dbo.DecisionMatterPersons", "DecisionPersonStatusId", c => c.Int(nullable: false, defaultValue: (int)DecisionAccess.Creator));
        CreateIndex("dbo.DecisionForm_DecisionFields", "DecisionAccessId");
        CreateIndex("dbo.DecisionMatterPersons", "DecisionPersonStatusId");
        //I moved outcommented to next migration and ran the migrations in separate steps to avoid: (The object is dependent on column ALTER TABLE ALTER COLUMN failed because one or more objects access this column)
        //AddForeignKey("dbo.DecisionForm_DecisionFields", "DecisionAccessId", "dbo.DecisionAccesses", "Id", cascadeDelete: true); 
        //AddForeignKey("dbo.DecisionMatterPersons", "DecisionPersonStatusId", "dbo.DecisionPersonStatus", "Id", cascadeDelete: true);
    }


    public override void Down()
    {
        //Moved to next migration
        //DropForeignKey("dbo.DecisionMatterPersons", "DecisionPersonStatusId", "dbo.DecisionPersonStatus");
        //DropForeignKey("dbo.DecisionForm_DecisionFields", "DecisionAccessId", "dbo.DecisionAccesses");
    }
2
Sgedda

移行が正しい順序であると仮定します。つまり、参照の前に外部キーに関連付けられたテーブルが作成されます。次の手順に従ってください:

  1. SQL Management Studioから現在のデータベースをバックアップします(必要な場合)
  2. SQL Management Studioからデータベースを削除する
  3. Visual Studioの「パッケージマネージャーコンソール」で「Update-Database」と入力します
1
Kuldeep Padhiar

このエラーは、子テーブルに孤立レコードがある場合にも発生する可能性があります。データベースをクリーンアップすると、問題が解決するはずです。

パッケージマネージャーコンソールでAdd-Migration InitialCreate –IgnoreChangesコマンドを実行します。これにより、現在のモデルをスナップショットとして空の移行が作成されます。

パッケージマネージャーコンソールでUpdate-Databaseコマンドを実行します。これにより、InitialCreate移行がデータベースに適用されます。実際の移行には変更が含まれていないため、この移行が既に適用されたことを示す行を__MigrationsHistoryテーブルに追加するだけです。

詳細については、こちらをご覧ください: https://msdn.Microsoft.com/en-us/library/dn579398(v = vs.113).aspx

0
Ersin

私もこのメッセージを受け取りました。問題は、データベース内のテストデータが正しくないことでした。私はテストしていたときに検証を持っていなかったため、nullを許可しないフィールドのIDにはnull値がありました。データを修正すると、update-databaseコマンドは正常に実行されました。

0
Fabian Madurai