EF Core 仅查询 DateTimeOffset 的 DateTime 无法翻译;
Posted
技术标签:
【中文标题】EF Core 仅查询 DateTimeOffset 的 DateTime 无法翻译;【英文标题】:EF Core query only DateTime of DateTimeOffset cannot be translated; 【发布时间】:2021-12-13 00:36:29 【问题描述】:我遇到了一个问题,我想仅基于 DateTimeOffset SQL Server 列的 DateTime 进行查询,我想知道是否可以使用 EF Core。
如果我在世界各地都有约会,并且我的业务逻辑将它们准确地记录在他们的本地 DateTimeOffset 中,我希望能够获得特定日期的约会,而不管时区如何,但是,我得到一个例外,即当我尝试以下操作时无法翻译查询:
public class Appointment
public int Id get;set;
public DateTimeOffset BeginTime get;set;
DateTime queryDay = new DateTime(2021, 1, 1);
var results = dbContext.Appointments.Where(a => a.BeginTime.DateTime >= queryDate && a.BeginTime.DateTime < queryDay.AddDays(1)).ToList();
有没有办法用 EF Core 做到这一点?我的意思是,在示例中,我只是想获得一个特定的日期,但实际上,我希望能够在任何日期时间使用任何时间值等来做到这一点。
换句话说,我不希望按通用时间范围进行过滤,而是按不考虑偏移量的时间范围进行过滤。
即使我创建了一个返回 BeginTime.DateTime 的 [NotMapped] 属性,它似乎也不起作用。
编辑:
确切的错误:
System.InvalidOperationException:LINQ 表达式 'DbSet() .Where(t => True && t.BeginTime.DateTime >= __fakeStartDate_1 && t.BeginTime.DateTime https://go.microsoft.com/fwlink/?linkid=2101038 了解更多信息。
【问题讨论】:
确切的错误是什么? 您是否尝试过预先计算 queryDay.AddDays(1) 并将其放入另一个变量(queryDayPlusOne)?这应该解决它,恕我直言。 为什么不对 queryDay 变量使用 DateTimeOffset?您可能必须创建类型为 DateTimeOffset 的 queryDayFrom 和 queryDayTo 变量。 @ErmiyaEskandary 添加了异常 @TomTom 没有解决它。这不是问题。我应该删除 .AddDays 以避免混淆 【参考方案1】:SqlServer 提供程序支持所谓的“双重转换”构造(首先到 object
,然后到其他类型,例如 (DateTime)(object)
),它欺骗 C# 编译器接受通常会失败的转换(如果在LINQ to Objects 上下文)和 EF Core 转换器,强制后者发出从 datetimeoffset
到 datetime2
using CAST
operator 的转换。
例如
var query = dbContext.Appointments
.Where(a => ((DateTime)(object)a.BeginTime) >= queryDate
&& ((DateTime)(object)a.BeginTime) < queryDate.AddDays(1));
成功转换为
DECLARE @__queryDate_0 datetime2 = '2021-01-01T00:00:00.0000000';
DECLARE @__AddDays_1 datetime2 = '2021-01-02T00:00:00.0000000';
SELECT [a].[Id], [a].[BeginTime]
FROM [Appointments] AS [a]
WHERE (CAST([a].[BeginTime] AS datetime2) >= @__queryDate_0) AND (CAST([a].[BeginTime] AS datetime2) < @__AddDays_1)
【讨论】:
如果列中存在索引,则列转换将排除查找,从而导致全扫描。 哇。非常感谢。它几乎是完美的,我可能会使用它,但是,如果像 @DanGuzman 说它会忽略索引,这将是一个性能问题,因为我在列上有索引。 先生,您能帮我解决这个问题吗:***.com/questions/69745866/… 当然索引会被忽略。但这与 OP 问题无关“EF Core 仅查询 DateTimeOffset 的 DateTime 无法翻译”。您想要DateTimeOffset.DateTime
属性的 SQL 翻译,并提供了答案(好像 EF Core 自然支持)。您定义它的方式,当前问题对我来说已关闭。如果您想要一种在数据库中寻找此类列的有效方法,那是完全不同的问题,因此需要创建新的 SO 问题。 @DanGuzman 您的评论是正确的,但与当前问题无关。【参考方案2】:
有一种我不太喜欢的方法,但它不能避免列上的索引,它应该可以工作。应该是这样的:
public IEnumerable<Appointments> GetAppointments(DateTime start, DateTime end)
var bufferStart = start.AddDays(-1);
var bufferEnd = end.AddDays(1);
return dbContext.Appointments
.Where(a => a.BeginTime >= bufferStart && a.BeginTime < bufferEnd)
.AsEnumerable()
.Where(a => a.BeginTime.DateTime >= start && a.BeginTime.DateTime < end);
显然,我不喜欢这个有很多原因,所以仍在寻找更好的答案。如果有人有的话将不胜感激。
【讨论】:
以上是关于EF Core 仅查询 DateTimeOffset 的 DateTime 无法翻译;的主要内容,如果未能解决你的问题,请参考以下文章
添加迁移时,IdentityServer DB 上的 EF Core 迁移适用于 MULTIPLE 表而不是仅 AspNetUsers 表