ASP.NET Core 3.1中EF/Linq结合NodaTime比较OffsetDateTime日期部分报错求解
问题原因
报错是因为EF Core 3.1 配套的NodaTime查询翻译器不支持直接解析OffsetDateTime.Date.Equals()方法的SQL转换。你之前添加AsEnumerable()没有生效是因为位置错误,该方法需要放在过滤条件之前才会触发客户端评估,但客户端评估会拉取全表数据,性能较差,优先推荐使用可被SQL翻译的查询写法。
解决方案
方案1:服务器端范围查询(推荐)
提前在内存计算出今日的时间区间,使用已验证可被翻译的Local.Compare方法做范围判断,可直接转成SQL执行,支持索引查询性能更高:
var zonedClock = SystemClock.Instance.InTzdbSystemDefaultZone(); OffsetDateTime now = zonedClock.GetCurrentOffsetDateTime(); // 计算今日零点对应的OffsetDateTime OffsetDateTime todayStart = now.Date.AtStartOfDayInZone(zonedClock.Zone).ToOffsetDateTime(); // 计算明日零点对应的OffsetDateTime作为区间上限 OffsetDateTime tomorrowStart = todayStart.PlusDays(1); return _context.Session .Where(x => Local.Compare(x.EndDateTime, now) < 0 && Local.Compare(x.StartDateTime, todayStart) >= 0 && Local.Compare(x.StartDateTime, tomorrowStart) < 0) .Include(o => o.Tournaments) .ToList<Session>();
方案2:客户端评估(仅适合小表场景)
调整AsEnumerable()的位置到过滤条件之前,让后续过滤逻辑在内存执行:
var zonedClock = SystemClock.Instance.InTzdbSystemDefaultZone(); OffsetDateTime now = zonedClock.GetCurrentOffsetDateTime(); return _context.Session .Include(o => o.Tournaments) // 此处触发客户端评估,后续Where逻辑在内存执行 .AsEnumerable() .Where(x => Local.Compare(x.EndDateTime, now) < 0 && x.StartDateTime.Date.Equals(now.Date)) .ToList<Session>();
注意:该方案会拉取全表的会话和关联赛事数据到内存再过滤,数据量大时会有严重性能问题,不建议生产环境大表使用。
内容的提问来源于stack exchange,提问作者Simon Aronson
相关产品推荐
相关产品推荐

