实体框架 ALTER TABLE 语句与 FOREIGN KEY 约束冲突
Posted
技术标签:
【中文标题】实体框架 ALTER TABLE 语句与 FOREIGN KEY 约束冲突【英文标题】:Entity Framework The ALTER TABLE statement conflicted with the FOREIGN KEY constraint 【发布时间】:2014-01-19 05:11:28 【问题描述】:在更新实体框架中的数据库,代码优先迁移时,我收到此错误:
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_dbo.Clients_dbo.MedicalGroups_MedicalGroupId 您在这一步之前是否更改了模型,在 Down() 案例中的情况如何?如果你做错了什么,你应该从数据库中删除前索引作为提及@brykneval @brykneval 名称没有问题,因为我确实更改了外键约束的名称但没有帮助!!! @AOZ 是的,我已经在数据库中添加了医疗组表。现在我想在客户和医疗集团之间建立联系。而且down()方法中没有代码 @AOZ 假设我做错了什么我怎么知道? 【参考方案1】:检查数据库中是否存在与 FK 约束冲突导致创建失败的数据。
【讨论】:
但是MedicalGroupId不是必须的..现有数据应该没有问题 @turnkey 是的,我的客户表中已经有数据,但我无法删除它。 @AOZ 有什么解决办法吗? 这不是删除数据,而是修复它们。如果有Client
引用不存在的MedicalGroup
,您将永远无法添加FK。
在我的情况下,我将外键属性设置为 int 而不是 int?所以 EF 添加了一个默认值 0,它指向外部表中没有条目。【参考方案2】:
我认为 @Cory 让您接近正确的解决方案,只是您没有花时间进行调查。
在 add-migration 代码中,可能会生成迁移
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 Column Add 那样更改现有数据,如果指定了默认值。
我建议您更改模型类以允许可为空的 int。 然后,在您的种子方法中,针对 dbcontext 创建一个简单的方法,以使用默认值更新新列,因为数据注释中的 [DefaultValue] 属性不会修改您的数据。
Add-Migration / Update-Database 创建列和约束。 接下来,如果您希望允许使用不可为空的 int,请修改您的模型,并假设您再次将所有行更改为外键的某个有效值,即 Add-Migration / Update-database。 这为您的模型迁移提供了一条完整的链。稍后当您发布到实时站点时会派上用场,因为您的数据模型更改流程将保持不变。
希望这会有所帮助。【讨论】:
我们在这里遇到了两步解决方案的问题。如果必须一次应用多个迁移,您最终会得到以下顺序:创建可为空的字段,使其不可为空,然后运行种子。没有地方可以真正将数据放入 FK 字段,一切都再次爆炸。我找到的唯一两个解决方案是从链接到 FK 的表中删除数据,或者使字段可为空并保持这种状态。 @AriRoth +1 但肯定还有另一种方式,这有多普遍?!【参考方案3】:这个错误告诉你你违反了外键约束。要解决你有几个解决方案
-
修复您的数据 -
Clients
表中的某处记录具有 MedicalGroupId,而
MedicalGroups
表。编写查询以找出哪些 ID 没有
存在于MedicalGroups
表中并手动修复数据
自己。
删除外键约束 - 显然,如果您删除外键约束,您将不再被此消息困扰。不幸的是,数据库将不再强制执行这种关系,并且将来可能会使这个问题变得更糟。
使用WITH NOCHECK
创建约束 - 您可以使用WITH NOCHECK
选项创建外键约束。此选项告诉 SQL Server 不要将此约束应用于现有数据。 SQL Server 将在以后的任何 INSERTS/UPDATES/DELETES 中检查此约束。
【讨论】:
【参考方案4】:对于可能出现在此处的其他人,如果您使用 Code-First Entity Framework 并且只是尝试将新的必需列添加到包含现有数据的表中,则可能会有一个非常简单的解决方法。
注意:在您执行此操作之前,只需知道您需要为所有现有行的此新列添加一个有效值。在继续之前,请考虑您将向现有行添加什么值。您可能希望向所需的查找表提供一个指示“无效”或“未知”的值。
在您的模型中,通过添加?在 int 之后。保存并编译模型。运行更新数据库。
示例:
[ForeignKey("Title")]
public int? TitleId get; set;
在数据库中,通过将 NULL 值替换为有效的查找值来更新表。在我的例子中,我将“未知”添加到我的标题查找表中,然后批量编辑所有行以引用该查找 ID。
返回您的模型,删除“?”所以该列不再可以为空。保存并编译模型,然后运行 Update-Database
您现在应该可以开始了。
【讨论】:
【参考方案5】:出现此问题是因为您的表不是空的。
所以你应该添加新字段而不像外键一样附加它。
public int? MedicalGroupId get; set;
.并在包管理控制台中执行update-database
命令。
然后用正确的数据填充此表(客户端)中的字段(值存在于 MedicalGroupsId 中)。
插入创建外键的行
[ForeignKey("MedicalGroupId")]
public virtual MedicalGroups MedicalGroup get return _MedicalGroup; set _MedicalGroup = value;
最后执行update-database
命令。会好的。
【讨论】:
【参考方案6】:我得到了我的问题的解决方案。问题是我在客户表中的“数据”。因为我的客户表具有实际不存在的医疗组 ID 值,这就是它在外键约束上给我错误的原因。
Update Client set MedicalGroupId = NULL
【讨论】:
在这种情况下,请将 Cory 或我的答案标记为解决方案,因为这是我们建议检查的内容。【参考方案7】:我在设置 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");
【讨论】:
【参考方案8】:假设您的迁移顺序正确,即与外键关联的表将在引用之前创建。请按照以下步骤操作:
-
从 SQL 管理工作室备份当前数据库(如果需要)
从 SQL 管理工作室中删除数据库
在 Visual Studio 的“包管理器控制台”中键入“更新数据库”
【讨论】:
【参考方案9】:如果子表中有孤立记录,也会发生此错误。清理数据库应该可以解决问题。
【讨论】:
【参考方案10】:在包管理器控制台中运行 Add-Migration InitialCreate –IgnoreChanges 命令。这会创建一个以当前模型作为快照的空迁移。
在包管理器控制台中运行 Update-Database 命令。这会将 InitialCreate 迁移应用到数据库。由于实际的迁移不包含任何更改,它只会在 __MigrationsHistory 表中添加一行,表明该迁移已被应用。
您可以在此处获取更多详细信息:https://msdn.microsoft.com/en-us/library/dn579398(v=vs.113).aspx
【讨论】:
【参考方案11】:我也收到了这条消息。问题是数据库中的测试数据不正确。 我在测试时没有验证,因此对于不允许空值的字段,我的 ID 为空值。修复数据后,update-database 命令运行成功。
【讨论】:
【参考方案12】:有这个问题,但幸运的是我只是在建表。我在每张桌子上只有几个样品。删除了两个表中的所有行,然后它就起作用了。我是菜鸟,所以值得一试
【讨论】:
【参考方案13】:您还可以通过
使用数据播种modelBuilder.Entity<MedicalGroups>()
.HasData(new MedicalGroups ... , new MedicalGroups ... )
在您的 DbContexts 类 OnModelCreating 方法中。
这样,您可以插入引用表中缺少 Id 的所有 MedicalData 行。至少在我的情况下,数据在需要时被播种并且更新数据库正常工作。
【讨论】:
以上是关于实体框架 ALTER TABLE 语句与 FOREIGN KEY 约束冲突的主要内容,如果未能解决你的问题,请参考以下文章
ALTER TABLE 语句与 FOREIGN KEY 约束冲突
如何用oracle里面的alter table语句去添加一个列约束