ChatGPT解决这个技术问题 Extra ChatGPT

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

在更新实体框架中的数据库时,代码优先迁移,我收到此错误:

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假设如果我做错了什么,我怎么知道?

T
Turnkey

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


但是MedicalGroupId不是强制性的。。现有数据应该没有问题
@turnkey 是的,我的客户表中已经有数据,但我无法删除它。
@AOZ那么有什么解决方案吗?
这不是关于删除数据,而是关于修复它们。如果存在引用不存在的 MedicalGroupClient,您将永远无法添加 FK。
在我的情况下,我将外键属性设置为 int 而不是 int?所以 EF 添加了一个默认值 0 ,它指向外部表中没有条目。
g
gdoron is supporting Monica

我认为@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,但肯定有另一种方式,这有多普遍?!
C
Cory

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

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


S
StuiterSlurf

出现此问题是因为您的表不是空的。所以你应该添加新字段而不像外键一样附加它。 public int? MedicalGroupId { get; set; }。并在包管理控制台中执行 update-database 命令。然后用正确的数据填充此表(客户端)中的字段(值存在于 MedicalGroupsId 中)。插入行以创建外键

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

最后执行 update-database 命令。会没事的。


G
GrayDwarf

对于可能出现在这里的其他人,如果您使用 Code-First Entity Framework 并且只是尝试将新的必需列添加到包含现有数据的表中,则可能会有一个非常简单的修复。

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

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

例子:

[ForeignKey("Title")] 公共整数?标题ID { 得到;放; }

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

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

你现在应该可以走了。


Z
Zaid Iqbal

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

Update Client set MedicalGroupId = NULL

在这种情况下,请将 Cory 或我的答案标记为解决方案,因为这是我们建议检查的内容。
S
Sgedda

我在设置 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");
    }

K
Kuldeep Padhiar

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

从 SQL 管理工作室备份当前数据库(如果需要)从 SQL 管理工作室删除数据库 在 Visual Studio 的“包管理器控制台”中键入“更新数据库”


C
Christopher Cabezudo Rodriguez

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


E
Ersin

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

在包管理器控制台中运行 Update-Database 命令。这会将 InitialCreate 迁移应用到数据库。由于实际迁移不包含任何更改,因此它只会在 __MigrationsHistory 表中添加一行,表明该迁移已被应用。

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


F
Fabian Madurai

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


T
Tim

有这个问题,但幸运的是我只是在建表。我在每张桌子上只有几个样品。删除了两个表中的所有行,然后它就起作用了。我是个菜鸟,所以要珍惜它的价值


J
Jens Mander

您还可以通过以下方式使用数据播种

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

在您的 DbContexts 类 OnModelCreating 方法中。

这样,您可以插入引用表中缺少 Id 的所有 MedicalData 行。至少在我的情况下,数据被播种到需要它并且更新数据库正常工作。