ASP.NET Core 中 HealthChecksDb 提示待迁移变更,如何排查?
结论
HealthChecksDb 来自 Xabaril 的 HealthChecks UI 数据层。你注册的 AddHealthChecksUI().AddPostgreSqlStorage(configString) 为 UI 配置了 PostgreSQL 存储,HealthChecks UI 默认启用数据库迁移。建议先检查这条注册链涉及的 context、迁移程序集和依赖版本。HealthChecksDb 源码、HealthChecks UI 存储与迁移配置
现有代码有助于定位组件,但缺少包版本、完整调用栈和模型快照,无法确定具体的模型差异。业务 context 生成了空迁移,也不能证明 HealthChecksDb 没有差异。
“pending changes”具体指什么?
这里比较的是 HealthChecksDb 当前构建的模型与迁移模型快照。这个提示不表示 EF Core 扫描数据库后发现某张表被手工修改。
需要区分两种情况:
- 待应用的迁移:迁移已经存在,但尚未执行到数据库。
- 待纳入迁移的模型变更:当前模型与迁移快照不一致,尚没有相应迁移记录这些差异。
PendingModelChangesWarning 针对后者。从 EF Core 9.0 开始,调用 Migrate()、MigrateAsync() 或执行 dotnet ef database update 时,这类差异默认会导致异常。题目未提供版本,因此需要先确认应用实际使用的 EF Core 版本。EF Core 9 迁移行为变更
HealthChecksDb 是 context 名称,表名由实体映射决定。没有名为 HealthCheck 的表,不能据此判断该 context 是否存在或是否需要迁移。
先确认发生异常的是哪个 context
在相应的项目目录中检查依赖和 context:
dotnet list package --include-transitive
dotnet ef dbcontext list
dotnet ef dbcontext info --context HealthChecksDb
多项目解决方案需要补充正确的 --project 和 --startup-project。如果 EF 工具无法创建设计时 context,应先解决设计时配置问题。这种失败不能说明运行时没有注册该 context。
重点核对以下依赖实际解析出的版本及其兼容范围:
AspNetCore.HealthChecks.UIAspNetCore.HealthChecks.UI.PostgreSQL.StorageMicrosoft.EntityFrameworkCore及相关包Npgsql.EntityFrameworkCore.PostgreSQL
版本不兼容是一个排查方向,目前无法确认它就是根因。选择兼容组合时,应查看各包声明的依赖范围,不能只看版本号是否相同。
再查看完整异常调用栈,找到迁移调用的位置。host.Run() 会启动已注册的服务,异常在此时暴露,不能证明模型变化是由后台线程引起的。
为什么添加的迁移是空的?
原描述中的 dotnet ef add 不是完整的添加迁移命令,通常应使用:
dotnet ef migrations add MigrationName --context ContextName
关键是命令实际选择了哪个 context。如果生成的迁移属于业务 context,空迁移只说明没有检测到该业务模型的差异,与 HealthChecksDb 的异常没有直接对应关系。
检查生成文件上的 DbContext 标记、对应的 ModelSnapshot 和运行时使用的迁移程序集。第三方存储包可以自带迁移,业务项目中的迁移文件并不覆盖它们。
要确定具体差异,需要在相同的 provider、模型配置和依赖版本下,对照 HealthChecksDb 的模型与其迁移快照。如果需要生成诊断迁移,建议在隔离的复现项目或存储组件源码副本中操作,避免把第三方 context 的迁移直接加入业务迁移目录。缺失快照、provider 不一致和不稳定的模型构建都可能触发该异常,但目前没有证据确定这里发生了哪一种情况。EF Core 官方排查说明
根据实际需求处理
只需要健康检查接口
如果既不使用 HealthChecks UI 仪表盘,也不使用历史记录,可以移除 UI 及其存储注册,保留健康检查:
services.AddHealthChecks()
.AddCheck("MyAppHealth", new HealthCheck(myapp));
原来的 MapHealthChecks(...) 可以继续提供检查结果。UIResponseWriter.WriteHealthCheckUIResponse 用于输出适合 UI 消费的 JSON;使用这个响应格式不要求在同一应用中部署 UI 存储。HealthChecks UI 响应格式说明
需要 UI,并由外部流程管理数据库
如果 UI 所需的表结构已经由部署流程创建并维护,可以关闭启动时自动迁移:
services.AddHealthChecksUI(setup =>
{
setup.DisableDatabaseMigrations();
})
.AddPostgreSqlStorage(configString);
这是组件提供的配置方式。它只关闭自动迁移,不会创建缺失的表,也不会修复模型和数据库之间的差异。表结构不满足要求时,后续读写仍可能失败。关闭 UI 数据库迁移
已确认检查属于误报,需要临时绕过
如果已经核对迁移和模型,确认可以暂时忽略该检查,且所用版本的 AddPostgreSqlStorage 提供 DbContextOptionsBuilder 配置回调,可以把配置限定在 UI 存储上:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
services.AddHealthChecksUI()
.AddPostgreSqlStorage(configString, options =>
{
options.ConfigureWarnings(w =>
w.Ignore(RelationalEventId.PendingModelChangesWarning));
});
ConfigureWarnings 是 EF Core 支持的处理方式,但是否应忽略取决于实际差异。仅仅配置了迁移程序集,不能据此认定是误报。忽略后,已有迁移仍可能执行,但未被迁移覆盖的模型变更不会自动补齐。EF Core 官方处理说明
还需要补充哪些信息?
如果兼容性和迁移配置都没有发现问题,应提供完整调用栈、上述包的实际版本,以及只包含 HealthChecks UI 和 PostgreSQL 存储的最小复现。不要通过反复添加业务空迁移、删除迁移历史或删除数据库来试错。
另外,MapHealthChecks("/myapp_health_ui", ...) 映射的是健康检查结果接口。路径中包含 ui 不会自动创建仪表盘;需要展示仪表盘时,还应配置 MapHealthChecksUI()。这与模型迁移异常是两个独立问题。HealthChecks UI 配置示例
备注:内容仅供参考。
