繁体   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