C#:为什么我的SQL查询中缺少一个.Where()条件?

时间:2017-08-18 10:00:39

标签: c# sql entity-framework

我有一个方法,运行以下代码行。它应该获取在过去24小时内创建的所有消息,并且未来不会创建(因为这不可能)。

messages.AddRange(_dbcontext.Messages
                .Where(message => message.CreationTime >= DateTime.UtcNow.AddHours(-24) && message.CreationTime <= DateTime.UtcNow)
                .ToList());

当应用程序运行并通过上面的行时,这是运行的SQL查询:

SELECT [message].[Id], [message].[CreationTime], [message].[Value]
FROM [Messages] AS [message]
WHERE([message].[CreationTime] <= GETUTCDATE())

这基本上检索所有消息,而不是过去24小时内创建的消息。

我想知道为什么Where()的这一部分被忽略或者没有被转换为SQL查询,以及我可以做些什么来使它工作。

(message => message.CreationTime >= DateTime.UtcNow.AddHours(-24)

2 个答案:

答案 0 :(得分:6)

这是先前2.0​​版EF核心版本(DateTimeAddHours等不支持的AddDays方法)中SQL查询转换的问题,导致所谓的client evaluation 。您的查询应该产生正确的结果,但是效率很低,因为在检索到与其他条件匹配的所有记录之后,where过滤器的第二部分将在内存中进行评估。

EF Core 2.0中进行了改进,生成的SQL看起来像这样(如预期的那样):

SELECT [message].[Id], [message].[CreationTime], [message].[Value]
FROM [Messages] AS [message]
WHERE ([message].[CreationTime] >= DATEADD(hour, -24E0, GETUTCDATE())) AND ([message].[CreationTime] <= GETUTCDATE())

因此要么升级到EF Core 2.0,要么使用通常的EF解决方法,将DateTime.UtcNow.AddHours(-24)置于查询之外的变量中并在其中使用。

答案 1 :(得分:2)

由于EF无法将DateTime操作转换为正确的SQL查询,我建议如下:

DateTime dayBefore = DateTime.UtcNow.AddHours(-24);
messages.AddRange(_dbcontext.Messages
                  .Where(message => message.CreationTime >= dayBefore && message.CreationTime <= DateTime.UtcNow)
                  .ToList());

我发现这个解决方案使用EF date and time canonical functions显然有效,但我还没有测试过:

messages.AddRange(_dbcontext.Messages
            .Where(message => message.CreationTime >= EntityFunctions.AddHours(DateTime.UtcNow, -24) && message.CreationTime <= DateTime.UtcNow)
            .ToList());

希望这有帮助。

修改

EntityFunctions已过时,已被DbFunctions取代,后面给出了以下示例。

messages.AddRange(_dbcontext.Messages
            .Where(message => message.CreationTime >= DbFunctions.AddHours(DateTime.UtcNow, -24) && message.CreationTime <= DateTime.UtcNow)
            .ToList());