PAYATHON 2026

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.UI
  • AspNetCore.HealthChecks.UI.PostgreSQL.Storage
  • Microsoft.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 配置示例

备注:内容仅供参考。