EF Core数据迁移需模型快照、DI链与数据库提供程序协同,常见错误如DbContext构造失败、Update-Database连错库、SQL生成异常及多人迁移冲突,须按规范配置无参构造、显式指定上下文与连接字符串、人工审查迁移脚本并严格同步历史表与文件。

EF Core 数据迁移不是“生成 SQL 就完事”的黑盒操作,它依赖模型快照、依赖注入链和数据库提供程序三者协同。用错一步,轻则迁移失败,重则生产库结构错乱或数据丢失。
dotnet ef migrations add 报 “Unable to create an object of type 'AppDbContext'”
这是最常卡住开发者的错误,本质是 CLI 无法构造你的 DbContext 实例。CLI 不走 Program.cs 的 DI 容器,而是尝试直接 new 实例,所以:
- 如果
AppDbContext构造函数依赖IConfiguration、ILogger或自定义服务,且这些没在无参构造中兜底,就会崩 - 多个
DbContext存在时,CLI 不知道选哪个,除非你显式传--context AppDbContext -
OnConfiguring没重写,又没提供无参构造,CLI 根本不知道连哪儿
解决方法:加一个仅用于迁移的无参构造(别删掉带 DbContextOptions 的那个):
public AppDbContext() : base(new DbContextOptionsBuilder<appdbcontext>()
.UseSqlServer("Server=.;Database=TestDb;Trusted_Connection=true;")
.Options)
{ }</appdbcontext>
或者更推荐的方式:用参数明确指定上下文和启动项目:
dotnet ef migrations add InitialCreate --project MyDataProject --startup-project MyWebProject --context AppDbContext
Update-Database 总是连错数据库
Update-Database 默认不读 appsettings.json 的默认连接字符串节,它优先使用 Program.cs 或 Startup.cs 中 UseSqlServer(或对应提供程序)硬编码的连接字符串。常见陷阱:
- 你在
appsettings.json改了ConnectionStrings:DefaultConnection,但Program.cs里还是写死的旧地址 - 用了
AddDbContextPool但没在UseSqlServer中传入Configuration.GetConnectionString(...) - 想切到测试库却忘了加
-c参数指定连接字符串
安全做法是显式传参:
dotnet ef database update -c "Server=localhost\SQLEXPRESS;Database=MyAppTest;Trusted_Connection=true;"
或者确保 Program.cs 中的注册逻辑真正读取配置:
builder.Services.AddDbContext<appdbcontext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")))</appdbcontext>
迁移文件里的 SQL 和你预期不一致
EF Core 迁移不是“实时查库生成”,而是比对当前模型和上一次 ModelSnapshot 文件。一旦你手动改过迁移里的 Up() 方法(比如加了 Sql("CREATE INDEX...")),后续再 add 新迁移时,EF Core 会把“你手改后的版本”当作新基准,导致差异计算出错。
- 字段类型从
string改成int?EF Core 默认生成ALTER COLUMN ... int NOT NULL,但原数据可能含空值或非数字字符 → 必须在Up()里先清理数据或设为可空 - 重命名列?默认是
DROP + ADD,不是sp_rename→ 数据全丢 - 删掉一个非空字段?EF Core 不会自动补
DEFAULT或UPDATE,得自己写Sql()
正确姿势:生成迁移后,立刻打开 Up() 方法人工审查,尤其注意涉及数据变更的操作;生产环境绝不直接 update,先用 dotnet ef migrations script 导出 SQL,DBA 审核后再执行。
多人协作时迁移冲突了怎么办
两个开发者各自 add 了同名时间戳前缀的迁移(如 20260401120000_AddUserEmail.cs),Git 合并时出现冲突,不能靠 IDE 自动解决。
- 别删别人的迁移文件——历史记录断了,
__EFMigrationsHistory表和代码就对不上 - 先
git pull拉最新代码,再dotnet ef database update确保本地库已同步到最新迁移状态 - 然后删掉你本地刚生成但还没 commit 的迁移文件(用
dotnet ef migrations remove最稳妥) - 再重新
add一次,得到新时间戳的迁移,此时它会基于最新快照生成差异
关键点:__EFMigrationsHistory 表是运行时权威,而 Migrations 文件夹是源码权威;两者必须严格一一对应,任何手动删表、删文件、改文件名,都会让 EF Core 下次 update 时彻底懵掉。











