Npgsql 10 让 Dapper 日期映射报错,先检查 DateOnly
Npgsql 10 默认读取 date 为 DateOnly,已有 Dapper DateTime 模型可能失败,可验证新类型契约或注册项目内兼容 resolver。
升级 Npgsql 10 后,Dapper 查询 PostgreSQL date 列,原来的 DateTime? 属性可能报 Error parsing column ... - DateOnly。错误文本里还显示了 24/11/2025,容易让人去调整 DateStyle 或日期字符串解析,实际需要先检查返回的 .NET 类型。
Npgsql 10 将 date 的默认读取类型改为 DateOnly,time 的默认读取类型改为 TimeOnly。旧版本默认返回的类型不同,已有映射器和模型可能无法直接接收新的对象。PostgreSQL 的 date 保存的是日期,错误消息中的显示格式不代表驱动正在按这个文本格式解析数据库值。
如果业务只表达日历日期,可以考虑让模型使用 DateOnly?,并核对 Dapper、UI 绑定及调用方是否支持它。不能只改一个属性,就假设所有过滤、计算和展示自动兼容。
需要保留旧默认类型时注册兼容 resolver
现有模型大量依赖 DateTime 时,可以使用 Npgsql 维护者提供的兼容 resolver 实现。将其中的 LegacyDateAndTimeResolverFactory.cs 复制进应用,再在构建数据源之前注册:
var builder = new NpgsqlDataSourceBuilder(connectionString);
builder.AddTypeInfoResolverFactory(
new LegacyDateAndTimeResolverFactory());
await using var dataSource = builder.Build();
LegacyDateAndTimeResolverFactory 是需要加入项目的兼容代码,不是 Npgsql 包里现成的内置类,也没有一个可直接写进连接字符串的“旧日期映射”开关。
这个实现处理默认对象读取的日期、时间以及相关数组和范围类型,影响不只一个 expirydate 字段。它使用了 Npgsql 的类型解析接口,升级驱动或改变部署方式时,需要重新编译并验证相应路径,不能当作跨版本永久保证。
如果应用已经使用共享数据源,应在该数据源的配置入口注册,不要每次请求都临时新建一个连接池。全局类型映射是另一种入口,但已有数据源的构建时机仍需核对;创建之后再修改配置,不会自动重建它。
保持日期的业务含义
不要为了让客户端重新收到 DateTime,就把数据库 date 列改成 timestamp。那会给原本没有时间的值引入另一种数据契约。手工把 DateOnly 转成 DateTime 时,也应明确时间部分和 Kind 的含义,不能凭空把日历日期当作 UTC 时刻。
验收应先查看读取对象的实际类型,再通过 Dapper 检查模型属性、NULL、已知日期和原有比较逻辑。采用兼容 resolver 时,还要覆盖项目使用到的时间、日期数组或范围;只看到一条查询不再报错,不足以判断整套默认映射都符合原有约定。


