实体框架ALTER TABLE语句与FOREIGN KEY约束冲突

时间:2014-01-01 17:40:22

标签: c# sql .net sql-server entity-framework

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

这是我的第二堂课:

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

12 个答案:

答案 0 :(得分:90)

检查数据库中是否存在与FK约束冲突的现有数据,导致创建失败。

答案 1 :(得分:28)

我认为@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");
}

注意可以为空:false;如果你的模型的Id为int而不是int? (nullable int)迁移代码将nullable设置为false。 您的模型显示您使用的是不可为空的int,默认为0,并且您可能没有值为0的外键项。

现在,您必须创建一个默认值,该值存在于外键表中, 或创建约束而不检查是否使用SQL Server创建约束。但要记住这一点:如果使用[DefaultValue(0)]属性装饰属性,则如果指定了默认值,它将不会更改现有数据,如SQL Column Add。

我建议您更改Model Class以允许可为空的int。 然后,在种子方法中,针对dbcontext创建一个简单方法,以使用默认值更新新列,因为数据注释中的[DefaultValue]属性不会修改您的数据。

添加 - 迁移/更新 - 数据库以创建列和约束。 接下来,如果您希望允许非可空int,并假设您已将所有行更改为外键的某个有效值,请再次修改模型,Add-Migration / Update-database。 这为您的模型迁移提供了一个完整的链。稍后当您发布到实际网站时会派上用场,因为您的数据模型更改流程将保持不变。

  • 希望这有帮助。

答案 2 :(得分:11)

此错误告诉您违反了外键约束。要解决你有一些解决方案

  1. 修复您的数据 - 某处Clients表中有 MedicalGroupId 的记录在该表中不存在 MedicalGroups表。编写查询以查找不具有的ID 存在于MedicalGroups表中并手动修复数据 自己。
  2. 删除外键约束 - 显然,如果删除外键约束,您将不再受此消息的困扰。不幸的是,数据库将不再强制执行这种关系,并可能在将来使这个问题变得更糟。
  3. 使用WITH NOCHECK创建约束 - 您可以使用WITH NOCHECK选项创建外键约束。此选项告诉SQL Server不将此约束应用于现有数据。 SQL Server将在以后的任何INSERTS / UPDATES / DELETES中检查此约束。

答案 3 :(得分:6)

出现此问题是因为您的表不为空。 所以你要添加新字段而不像外键那样附加它。 public int? MedicalGroupId {get;组; } 。并在包管理控制台中执行update-database命令。 然后使用正确的数据填充此表(客户端)中的字段(值存在于MedicalGroupsId中)。 插入该行以创建外键 的 [ForeignKey的(" MedicalGroupId&#34)]     public virtual MedicalGroups MedicalGroup {get {return _MedicalGroup; } set {_MedicalGroup = value; }} 。 最后执行update-database命令。没关系。

答案 4 :(得分:2)

我得到了我的问题的解决方案。问题是我在客户表中的“数据”。因为我的客户端表具有实际上不存在的medicalgroupid值,这就是为什么它给我外键约束的错误。

Update Client set MedicalGroupId = NULL

答案 5 :(得分:2)

我在设置defaultValue时遇到了这个问题,给出了:

“该对象依赖于列ALTER TABLE ALTER COLUMN失败,因为一个或多个对象访问此列”。

结束将AddForeignKey / DropForeignKey移动到新的迁移并在单独的update-database命令中运行它们(不要在一个命令中执行两次迁移,然后它就失败了。)

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

答案 6 :(得分:2)

对于可能在此处着陆的其他人,如果您正在使用代码优先实体框架并且只是尝试向具有现有数据的表添加新的必需列,则可能会有一个非常简单的修复。

注意:在执行此操作之前,只需知道您需要为所有现有行的新列添加有效值。考虑在继续之前您将添加到现有行的值。您可能希望提供一个表示"无效"或"未知"到所需的查找表。

在您的模型中,通过添加?将列设置为可为空?在int之后。保存并编译模型。运行Update-Database。

实施例:



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




在db中,通过将NULL值替换为有效的查找值来更新表。就我而言,我添加了#34;未知"到我的标题查找表,然后批量编辑所有行以引用该查找标识。

返回您的模型,删除'?'所以该列不再可以为空。保存并编译模型,然后运行Update-Database

你现在应该好好去。

答案 7 :(得分:1)

假设您的迁移顺序正确,即在引用之前将创建与外键关联的表。请按照以下步骤操作:

  1. 从SQL管理工作室备份当前数据库(如果需要)
  2. 从SQL管理工作室删除数据库
  3. 在Visual Studio'软件包管理器控制台中键入'更新 - 数据库'

答案 8 :(得分:0)

在程序包管理器控制台中运行 Add-Migration InitialCreate -IgnoreChanges 命令。这会创建一个空迁移,并将当前模型作为快照。

在程序包管理器控制台中运行更新数据库命令。这将将InitialCreate迁移应用于数据库。由于实际迁移不包含任何更改,因此只需在__MigrationsHistory表中添加一行,表示已应用此迁移。

您可以在此处获得更多详细信息:https://msdn.microsoft.com/en-us/library/dn579398(v=vs.113).aspx

答案 9 :(得分:0)

如果子表中有孤立记录,也会发生此错误。清理数据库应该可以解决问题。

答案 10 :(得分:0)

我也收到了此消息。问题是数据库中的测试数据不正确。 我没有在测试时进行验证,因此对于不允许为null的字段,ID的值为null。修复数据后,update-database命令成功运行。

答案 11 :(得分:0)

有这个问题,但幸运的是我只是在构建我的桌子。我在每张桌子上只有几个示例项目。删除了两个表中的所有行然后它工作了。我是菜鸟,所以物有所值

相关问题