You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Code First执行Update-Database时遇外键约束冲突异常求解决

问题:Entity Framework迁移时外键约束冲突

模型代码

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace web_template_001.Models
{
    public class Movie
    {
        [Required]
        public int Id { get; set; }
        [Required]
        [StringLength(25)]
        public string Title { get; set; }
        [Required]
        public Genre Genre { get; set; }
        public byte GenreId { get; set; }
        public DateTime DateAdded { get; set; }
        public DateTime ReleaseDate { get; set; }
        public byte NumberInStock { get; set; }
    }

    public class Genre
    {
        [Required]
        public byte Id { get; set; }
        [Required]
        [StringLength(25)]
        public string Name { get; set; }
    }
}

迁移代码

namespace web_template_001.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class ModifiedMovieProperties : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Genres",
                c => new
                    {
                        Id = c.Byte(nullable: false),
                        Name = c.String(nullable: false, maxLength: 25),
                    })
                .PrimaryKey(t => t.Id);
            
            AddColumn("dbo.Movies", "GenreId", c => c.Byte(nullable: false));
            AddColumn("dbo.Movies", "DateAdded", c => c.DateTime(nullable: false));
            AddColumn("dbo.Movies", "ReleaseDate", c => c.DateTime(nullable: false));
            AddColumn("dbo.Movies", "NumberInStock", c => c.Byte(nullable: false));
            CreateIndex("dbo.Movies", "GenreId");
            AddForeignKey("dbo.Movies", "GenreId", "dbo.Genres", "Id", cascadeDelete: true);
        }
        
        public override void Down()
        {
            DropForeignKey("dbo.Movies", "GenreId", "dbo.Genres");
            DropIndex("dbo.Movies", new[] { "GenreId" });
            DropColumn("dbo.Movies", "NumberInStock");
            DropColumn("dbo.Movies", "ReleaseDate");
            DropColumn("dbo.Movies", "DateAdded");
            DropColumn("dbo.Movies", "GenreId");
            DropTable("dbo.Genres");
        }
    }
}

执行Update-Database时的错误

The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Movies_dbo.Genres_GenreId". The conflict occurred in database "aspnet-web_template_001-20230102051540", table "dbo.Genres", column 'Id'.

已尝试删除迁移重新创建、重启Visual Studio,问题仍未解决,此前用相同方法关联其他模型外键正常,寻求解决方案。


解决方案

错误核心原因:添加非空GenreId外键列时,现有Movies表数据会被自动填充Byte类型默认值0,但刚创建的Genres表没有Id为0的记录,导致外键约束冲突。

方法一:修改迁移代码分阶段执行

先添加允许为空的外键列,插入默认Genre数据,再更新Movies表的GenreId为合法值,最后修改列为非空并添加约束:

public override void Up()
{
    // 1. 创建Genres表并插入默认数据
    CreateTable(
        "dbo.Genres",
        c => new
            {
                Id = c.Byte(nullable: false),
                Name = c.String(nullable: false, maxLength: 25),
            })
        .PrimaryKey(t => t.Id);
    
    // 插入一条合法Genre记录
    Sql("INSERT INTO dbo.Genres (Id, Name) VALUES (1, 'Default Genre')");

    // 2. 添加允许为空的GenreId列及其他列
    AddColumn("dbo.Movies", "GenreId", c => c.Byte());
    AddColumn("dbo.Movies", "DateAdded", c => c.DateTime(nullable: false));
    AddColumn("dbo.Movies", "ReleaseDate", c => c.DateTime(nullable: false));
    AddColumn("dbo.Movies", "NumberInStock", c => c.Byte(nullable: false));

    // 3. 更新现有Movies的GenreId为合法值
    Sql("UPDATE dbo.Movies SET GenreId = 1 WHERE GenreId IS NULL");

    // 4. 修改GenreId列为非空,添加索引和外键
    AlterColumn("dbo.Movies", "GenreId", c => c.Byte(nullable: false));
    CreateIndex("dbo.Movies", "GenreId");
    AddForeignKey("dbo.Movies", "GenreId", "dbo.Genres", "Id", cascadeDelete: true);
}

方法二:清空测试环境Movies数据(仅适用于测试场景)

若数据库中Movies数据无保留价值,可先删除所有记录再创建外键:

public override void Up()
{
    CreateTable(
        "dbo.Genres",
        c => new
            {
                Id = c.Byte(nullable: false),
                Name = c.String(nullable: false, maxLength: 25),
            })
        .PrimaryKey(t => t.Id);
    
    Sql("INSERT INTO dbo.Genres (Id, Name) VALUES (1, 'Default Genre')");
    
    // 删除现有Movies数据
    Sql("DELETE FROM dbo.Movies");

    AddColumn("dbo.Movies", "GenreId", c => c.Byte(nullable: false));
    AddColumn("dbo.Movies", "DateAdded", c => c.DateTime(nullable: false));
    AddColumn("dbo.Movies", "ReleaseDate", c => c.DateTime(nullable: false));
    AddColumn("dbo.Movies", "NumberInStock", c => c.Byte(nullable: false));
    CreateIndex("dbo.Movies", "GenreId");
    AddForeignKey("dbo.Movies", "GenreId", "dbo.Genres", "Id", cascadeDelete: true);
}

修改完成后,重新执行Update-Database命令即可完成迁移。


内容的提问来源于stack exchange,提问作者Joshua Mitchum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 20:25:59