ef core code first迁移需显式执行add-migration和update-database;前者生成迁移类与modelsnapshot快照,后者才真正同步数据库结构,跳过任一命令均会导致模型不一致异常。

EF Core 的 Code First 迁移不是“改完模型就自动同步”,而是必须显式执行 Add-Migration 和 Update-Database 两个命令,缺一不可;跳过迁移直接运行程序,90% 以上会触发 InvalidOperationException: The model backing the context has changed。
为什么 Add-Migration 后还要 Update-Database
Add-Migration 只生成迁移类(如 20260425145023_InitialCreate.cs)和 Migrations/ModelSnapshot.cs 快照文件,它不碰数据库——只是把当前模型“拍个照”并记录差异。真正建表、加字段、改约束,全靠 Update-Database 执行快照与数据库之间的差值。
常见误解:
- 误以为
Add-Migration会自动建库 → 实际不会,连连接字符串错误都不会报 - 在开发中删掉
Migrations文件夹重来 → 快照丢失,后续所有迁移都会失效 - 改了实体后只跑
Update-Database不跑Add-Migration→ 立刻抛出模型变更异常
模型改了但没加迁移,启动就崩怎么办
典型场景:给 Blog 类加了 public string Url { get; set; },没执行 Add-Migration 就直接启动 Web API 或调用 SaveChanges(),EF Core 检测到模型(含 Url)和快照(不含 Url)不一致,且数据库也无该列,直接拒绝初始化上下文。
修复步骤只有且必须是:
- 在 PMC 或 CLI 中执行
Add-Migration AddUrlToBlog(名字可自定义,但建议语义化) - 检查生成的
Up(MigrationBuilder migrationBuilder)方法里是否真有migrationBuilder.AddColumn<string>("Url", "Blogs", ...)</string> - 再执行
Update-Database(开发环境可直接跑,生产环境务必先导出 SQL) - 切勿手动在数据库里加字段 → 快照仍不匹配,下次迁移还会出错
生产环境不能直接 Update-Database
Update-Database 在生产库上执行等同于“裸奔上线”:没有审核、无法回滚、可能锁表、甚至因类型变更(如 int → string)导致数据丢失。
正确做法是导出可控脚本:
- 生成完整迁移 SQL:
dotnet ef migrations script --idempotent(含判断逻辑,可重复执行) - 只导某次迁移:
dotnet ef migrations script InitialCreate AddUrlToBlog - PMC 对应命令:
Script-Migration InitialCreate AddUrlToBlog - 拿到 SQL 后交 DBA 审核,再人工在目标库执行
注意:--idempotent 参数不是万能的——它不处理数据迁移逻辑(比如字段拆分、枚举转字符串),这类操作需在 Up() 方法里手写 Sql() 或 ExecuteSqlRaw()。
ModelSnapshot 是迁移的唯一真相源
Migrations/ModelSnapshot.cs 不是日志,而是 EF Core 判断“模型有没有变”的唯一依据。每次 Add-Migration 都会重写它,覆盖为当前模型的完整结构。
容易被忽略的点:
- 合并分支时若冲突没解决干净,
ModelSnapshot出现重复类或语法错误 → 后续所有迁移命令都失败 - 手动删掉它想“重置” → EF Core 会报
Unable to find a constructor to use for type ...ModelSnapshot - 它不记录数据,也不参与运行时性能,但少了它,迁移链就断了
最稳妥的做法:把它当普通代码维护,提交进 Git,冲突时以最新模型为准手工合并。











