【问题标题】:C#: Why is one of my .Where() conditions missing in my SQL query?C#:为什么我的 SQL 查询中缺少我的 .Where() 条件之一?
【发布时间】:2017-08-18 10:00:38
【问题描述】:

我有一个正在运行以下代码行的方法。它应该获取在过去 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)

【问题讨论】:

  • 我认为这两个查询结果与都为您提供最近 24 小时记录的数据相同。我不确定实体框架优化是否可以做到这一点。
  • @AmitSingh 该 SQL 查询如何只返回最近 24 小时的记录?
  • 尝试声明一个分配此日期的变量DateTime.UtcNow.AddHours(-24),并在您的实体查询中使用此变量。 AFAIK 实体无法直接翻译此内容
  • @Misery 这也是我的想法,但问题就变成了为什么实体框架(这是实体框架,不是吗?@SimonP?)抱怨这一点,就像它处理其他事情一样无法转换。
  • @LasseV.Karlsen 如果列中存储的日期是 utc 格式。

标签: c# sql entity-framework


【解决方案1】:

这是 EF Core 2.0 之前版本中的 SQL 查询翻译问题(不支持的 DateTime 方法,如 AddHoursAddDays 等),导致所谓的 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) 放入查询外部的变量中并在内部使用。

【讨论】:

    【解决方案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());
    

    【讨论】:

      猜你喜欢
      • 2019-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多