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

Zai*_*bal 49 .net c# sql sql-server 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; } }
}
Run Code Online (Sandbox Code Playgroud)

这是我的第二堂课:

public partial class MedicalGroups
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是我试图应用的迁移:

public override void Up()
{
    AddForeignKey("dbo.Clients", "MedicalGroupId", "dbo.MedicalGroups", "Id");
    CreateIndex("dbo.Clients", "MedicalGroupId");
}
Run Code Online (Sandbox Code Playgroud)

Tur*_*key 95

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

  • 它不是关于删除数据,而是关于修复它们.如果有'Client`参考不存在的`MedicalGroup`,你将永远无法添加FK. (5认同)
  • 但是MedicalGroupId不是强制性的。现有数据应该没有问题 (2认同)
  • 就我而言,我已将外键属性设置为 int 而不是 int?因此 EF 添加了默认值 0,它指向外部表中没有条目。 (2认同)

小智 31

我认为@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");
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  • 希望这可以帮助.

  • 我们在这里遇到了两步解决方案的问题.如果必须同时应用多个迁移,则最终得到以下顺序:创建可空字段,使其不可为空,然后运行种子.实际上没有地方可以将数据放入FK字段,所有内容都会再次爆炸.我发现的唯一两个解决方案是从表中删除链接到FK的数据,或者使字段可以为空并保持这种方式. (2认同)

Cor*_*ory 11

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

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


Gra*_*arf 9

对于可能出现在这里的其他人,如果您使用代码优先实体框架并且只是尝试将新的必需列添加到具有现有数据的表中,则可能有一个非常简单的修复方法。

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

在您的模型中,通过添加 ? 在 int 之后。保存并编译模型。运行更新数据库。

例子:

[ForeignKey("Title")]
public int? TitleId { get; set; }
Run Code Online (Sandbox Code Playgroud)

在数据库中,通过用有效的查找值替换 NULL 值来更新表。就我而言,我在标题查找表中添加了“未知”,然后批量编辑所有行以引用该查找 ID。

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

你现在应该可以走了。


小智 6

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


Zai*_*bal 4

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

Update Client set MedicalGroupId = NULL
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,请将科里或我的答案标记为解决方案,因为这就是我们建议检查的内容。 (3认同)