首页 > 解决方案 > 执行 Select 时在 EF Core 3 中将 Day 添加到 DateTime

问题描述

我正在尝试使用 EF Core 3 查询数据库,按日期和小时对 DateTime 字段进行分组,并将小时部分添加到 Select 上的日期。到目前为止,我所有的 Linqs 都失败了。

失败案例 1. 使用 AddHours 添加小时数。

Logs.GroupBy(g => new
{
    g.DateStamp.Date,
    g.DateStamp.Hour,
    g.Result
}).Select(s => new
{
    Date = s.Key.Date.AddHours(s.Key.Hour),
    s.Key.Result,
    Conversions = s.Count(),
    Cost = s.Sum(sum => sum.ConversionCost)
}).OrderBy(o => o.Date)

错误:

对于数据类型 date,日期函数 dateadd 不支持 datepart 小时。

不确定问题出在哪里,Linq to Entity 提供程序不支持 AddHours,或者 s.Key.Date 字段不能再包含小时,因为它变成了仅限日期的字段。

失败案例 2. 创建新的 DateTime 对象并传递变量。

Logs.GroupBy(g => new
{
    g.DateStamp.Date,
    g.DateStamp.Hour,
    g.Result
}).Select(s => new
{
    Date =new DateTime(s.Key.Date.Year, s.Key.Date.Month, s.Key.Date.Day,  s.Key.Hour, 0, 0),   
    s.Key.Result,
    Conversions = s.Count(),
    Cost = s.Sum(sum => sum.ConversionCost)
}).OrderBy(o => o.Date)

错误:

Cost = Sum(source: e, selector: (sum) => sum.ConversionCost) }), keySelector: (e0) => e0.Date)' 无法翻译。以可翻译的形式重写查询,或通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用显式切换到客户端评估。看 https://go.microsoft.com/fwlink/?linkid=2101038了解更多信息。

OrderBy(o => o.Date)停止工作并给出异常,为什么?我也不知道。

所以最后一个问题是,如何使用 EF Core 按 Date+Hour 对 SQL 数据库中的 DateTime 字段进行分组,并将其移动到 Select 到一个字段中,并在最后按新的 Date 字段执行 OrderBy。

标签: linqentity-framework-corelinq-to-entities

解决方案


我可以对失败案例 1 发表评论,因为我也遇到了同样的问题。

  1. x.Date转换为 sql 为CONVERT(date, x)
  2. x.AddHours(y)转换为 sql 为DATEADD(hour, x, y)
  3. 我们两者都有,所以这是DATEADD(hour, CONVERT(date, x), y)不可能的,因为您不能将小时数添加到类型的数据中,date因此会出现错误消息。

在 sql 级别上,它通常通过添加额外的强制转换来修复datetime2,比如

CAST(CONVERT(date, x) AS datetime2)

因此,您datetime2再次在水平上进行交易,并能够为结果值增加小时数。

话虽如此,我不知道如何强制 EF 生成额外的演员表(两者(DateTime)Convert.ToDateTime没有帮助),所以这是我想出的解决方法(不能说它是否会因溢出而失败)

   x.AddMilliseconds(-EF.Functions.DateDiffMillisecond(TimeSpan.Zero, x.TimeOfDay))
    .AddHours(y)

使用 EF Core 3.1.12 对其进行了测试,它按预期对我有用。这是输出

(DATEADD(
    hour, 
    CAST(y AS int), 
    DATEADD(
        millisecond, 
        CAST(
            CAST(
                -DATEDIFF(MILLISECOND, '00:00:00', CAST(x AS time)) AS float) AS int
            ), 
        x
    )
)

会猜测案例 2 失败,因为 EF 无法翻译new DateTime表达式,但这只是一个神秘的错误。


推荐阅读