EF Core中如何通过LINQ比较NodaTime.Period(PostgreSQL存储为interval)
解决方案
核心问题分析
NodaTime Period 是日历相关的时长(如“1个月”会因月份天数不同而变化),而PostgreSQL interval 是绝对时长,EF Core Npgsql提供程序对两者的比较翻译依赖于版本支持。你的问题主要源于包版本兼容性或未使用正确的LINQ翻译方式。
解决步骤
1. 升级Npgsql相关包
确保使用与.NET 8兼容的最新稳定版:
Npgsql.EntityFrameworkCore.PostgreSQL(8.x版本)Npgsql.NodaTime(8.x版本)
旧版本可能缺失Period比较的SQL翻译逻辑。
2. 直接使用Period比较(推荐)
升级包后,EF Core会自动将Period的比较运算符翻译为PostgreSQL的interval比较,直接编写LINQ即可:
var givenPeriod = Period.FromHours(8); var matchingEntities = await ctx.Entities .Where(e => e.Period <= givenPeriod) .ToListAsync();
3. 若直接比较不符合预期,转Duration查询
如果需要基于绝对时长比较(忽略日历差异),可使用ToDuration()方法,该方法已被EF Core Npgsql提供程序支持翻译为SQL:
var givenDuration = givenPeriod.ToDuration(); var matchingEntities = await ctx.Entities .Where(e => e.Period.ToDuration() <= givenDuration) .ToListAsync();
4. 修复原生SQL查询问题
若暂时需要原生SQL,必须使用参数化查询,让Npgsql自动处理Period到interval的转换(硬编码字符串会导致类型不匹配):
var givenPeriod = Period.FromHours(8); var matchingEntities = await ctx.Entities .FromRawSql(@"SELECT * FROM ""Entities"" WHERE ""Period"" <= @p0", givenPeriod) .ToListAsync();
DbContext配置说明
你当前的配置是正确的,无需额外修改:
services.AddDbContext<MyCtx>(opt => opt.UseNpgsql(conn, npgOpt => npgOpt.UseNodaTime()) );
UseNodaTime()会自动启用NodaTime类型与PostgreSQL类型的映射,包括Period到interval的转换。
内容的提问来源于stack exchange,提问作者Joshit
相关产品推荐
相关产品推荐

