簡體   English   中英

實體框架 ALTER TABLE 語句與 FOREIGN KEY 約束沖突

[英]Entity Framework The ALTER TABLE statement conflicted with the FOREIGN KEY constraint

在 Entity Framework 中更新數據庫時,代碼優先遷移,我收到此錯誤:

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

這是我的第二堂課:

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

檢查數據庫中是否存在與 FK 約束沖突導致創建失敗的現有數據。

我認為@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; 如果您的模型的 ID 是 int 而不是 int? (nullable int) 遷移代碼會將 nullable 設置為 false。 您的模型顯示您正在使用默認為 0 的不可為空的 int,並且您可能沒有值為 0 的外鍵項。

現在,您必須創建一個存在於外鍵表中的默認值,或者創建約束而不檢查是否使用 SQL Server 創建約束。 不過請記住:如果您使用 [DefaultValue(0)] 屬性裝飾您的屬性,則它不會更改現有數據,就像 SQL 列添加一樣,如果指定了默認值。

我建議您更改模型類以允許可以為空的 int。 然后,在您的種子方法中,針對 dbcontext 創建一個簡單的方法以使用默認值更新新列,因為數據注釋中的 [DefaultValue] 屬性不會修改您的數據。

Add-Migration / Update-Database 創建列和約束。 接下來,如果您希望允許不可為空的 int,並假設您將所有行更改為外鍵的某個有效值,請修改您的模型,再次添加遷移/更新數據庫。 這為您的模型遷移提供了一條不間斷的鏈條。 稍后當您發布到實時站點時會派上用場,因為您的數據模型更改流將保持不變。

  • 希望這會有所幫助。

這個錯誤告訴你你違反了外鍵約束。 要解決您有幾個解決方案

  1. 修復您的數據- Clients表中某處的記錄具有MedicalGroups表中不存在的MedicalGroups 編寫查詢以找出MedicalGroups表中不存在哪些 ID 並自己手動修復數據。
  2. 刪除外鍵約束- 顯然,如果刪除外鍵約束,您將不再受到此消息的困擾。 不幸的是,數據庫將不再強制執行這種關系,並且將來可能會使這個問題變得更糟。
  3. 使用WITH NOCHECK創建約束- 您可以使用WITH NOCHECK選項創建外鍵約束。 此選項告訴 SQL Server 不對現有數據應用此約束。 SQL Server 將在以后的任何 INSERTS/UPDATES/DELETES 中檢查此約束。

對於可能出現在這里的其他人,如果您使用代碼優先實體框架並且只是嘗試將新的必需列添加到具有現有數據的表中,則可能有一個非常簡單的修復方法。

注意:在執行此操作之前,只需知道您需要為所有現有行的此新列添加一個有效值。 在繼續之前考慮將向現有行添加什么值。 您可能希望為所需的查找表提供一個指示“無效”或“未知”的值。

在您的模型中,通過添加 ? 在 int 之后。 保存並編譯模型。 運行更新數據庫。

例子:

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

在數據庫中,通過用有效的查找值替換 NULL 值來更新表。 就我而言,我在標題查找表中添加了“未知”,然后批量編輯所有行以引用該查找 ID。

回到您的模型中,刪除“?” 所以該列不再可以為空。 保存並編譯模型,然后運行 ​​Update-Database

你現在應該可以走了。

出現此問題是因為您的表不為空。 所以你應該添加新字段而不像外鍵一樣附加它。 public int? MedicalGroupId { get; set; } public int? MedicalGroupId { get; set; } 。而執行update-database中包命令管理控制台。 然后用正確的數據填充此表(客戶端)中的字段(值存在於 MedicalGroupsId 中)。 插入用於創建外鍵的行

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

最后執行update-database命令。 會沒事的。

我得到了我的問題的解決方案。 問題是我的客戶表中的“數據”。 因為我的客戶端表具有實際上並不存在的醫療組 ID 值,這就是為什么它在外鍵約束上給我錯誤。

Update Client set MedicalGroupId = NULL

我在設置 defaultValue 時也遇到了這個問題,給出了:

“該對象依賴於列 ALTER TABLE ALTER COLUMN 失敗,因為一個或多個對象訪問此列”。

最終將 AddForeignKey/DropForeignKey 移動到新的遷移並在單獨的更新數據庫命令中運行它們(不要在一個命令中執行兩個遷移然后它對我來說失敗了。)

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

假設您的遷移順序正確,即與外鍵關聯的表將在引用之前創建。 請按照以下步驟操作:

  1. 從 SQL 管理工作室備份當前數據庫(如果需要)
  2. 從 SQL 管理工作室刪除數據庫
  3. 在 Visual Studio 的“包管理器控制台”中鍵入“更新數據庫”

在包管理器控制台中運行Add-Migration InitialCreate –IgnoreChanges命令。 這將創建一個以當前模型作為快照的空遷移。

在包管理器控制台中運行Update-Database命令。 這會將 InitialCreate 遷移應用到數據庫。 由於實際遷移不包含任何更改,因此它只會向 __MigrationsHistory 表添加一行,表明此遷移已被應用。

您可以在此處獲得更多詳細信息: https : //msdn.microsoft.com/en-us/library/dn579398(v=vs.113).aspx

如果子表中有孤立記錄,也會發生此錯誤。 清理數據庫應該可以解決問題。

我也收到了這個消息。 問題是db中的測試數據不正確。 我在測試時沒有驗證,因此對於不允許為空的字段,我的 ID 為空值。 一旦我修復了數據,update-database 命令就成功運行了。

有這個問題,但幸運的是我只是在建我的桌子。 我在每張桌子上只有幾個示例項目。 刪除兩個表中的所有行然后它工作。 我是個菜鳥,所以就物有所值吧

您還可以通過使用數據播種

modelBuilder.Entity<MedicalGroups>()
.HasData(new MedicalGroups { ... }, new MedicalGroups { ... })

在您的 DbContexts 類 OnModelCreating 方法中。

這樣您就可以插入引用表中缺少 Id 的所有 MedicalData 行。 至少在我的情況下,數據被播種了,這是需要的,並且更新數據庫正常工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM