You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:43:17