EF Core使用延迟执行和SQL侧分组的Group By功能

3
使用支持 Group By 翻译的 EF Core 2.1 版本,但是在对键值进行投影之后不再支持 Group By 翻译。
我需要一个查询支持各种不同的分组类型和聚合类型:
分组类型包括:年份、年/月、年/月/日等。
聚合类型包括:平均值、总和、最小值、最大值等。
我创建了两个 switch 语句,一个用于分组,一个用于聚合。我的问题在于我无法延迟执行并在 SQL 中执行分组。否则,结果数据集会非常大。
这是一种合理的方法吗?还是应该使用原始查询?
这个查询已经按照要求进行了延迟和分组,但键类型只适用于年/月,并且如果我想按照其他类型进行分组(例如年/月/日),就无法提供第二个 switch 中聚合的通用解决方案。
var query1 = series
     .GroupBy(k => new { k.Created.Year, k.Created.Month, });

var result1 = query1
    .Select(i => new { i.Key, Value = i.Average(a => a.DataValue) });

一旦将密钥转换为字符串,客户端就会进行分组:
var query2 = series
      .GroupBy(k => k.Created.Year.ToString());

var result2 = query2
    .Select(i => new { i.Key, Value = i.Average(a => a.DataValue) });

这也会导致客户端发生分组:
var query3 = series
     .GroupBy(k => new { k.Created.Year, k.Created.Month, })
     .Select(i => new
     {
         Key = $"{i.Key.Year}-{i.Key.Month}",
         Values = i.ToList()
     });

有什么想法可以完成我的查询?理想情况下,我需要一个通用的组键,可以对服务器端进行分组或通过查询中的函数传递聚合。生成基于字符串的键似乎可以确保在客户端进行分组。


由于我认为没有通用解决方案,想知道这里的“等等”可能是什么,“按年份分组:年份、年/月、年/月/日等”。 - Ivan Stoev
@IvanStoev 完整的列表包括年、年/月、年/月/日、年/月/日/小时、月、月份中的日期、每月的日期、一周中的日期。 - andleer
有点棘手。我认为我可以处理所有这些,除了星期几,即使你只按它分组,也无法将其翻译成SQL。 - Ivan Stoev
整个项目有点像概念验证。如果需要,可以排除星期几。老实说,我认为这很可能需要使用原始的SQL方法,而我可以处理。 - andleer
1个回答

4

我唯一能够在EF Core 2.1(和2.2)中获得SQL翻译的方法是按条件分组复合匿名类型,包括所需的数据部分:

bool includeYear = ...;
bool includeMonth = ...;
bool includeDay = ...;
bool includeHour = ...;

var query1 = series
    .GroupBy(e => new
    {
        Year = includeYear ? e.CreatedDate.Year : 0,
        Month = includeMonth ? e.CreatedDate.Month : 0,
        Day = includeDay ? e.CreatedDate.Day : 0,
        Hour = includeHour ? e.CreatedDate.Hour : 0
    });

很奇怪的是,如果我为组键创建一个特殊的类,该类具有与匿名类型完全相同的属性,并将new {...}更改为new MyKeyType{...},EF Core就会切换到客户端评估。

简而言之,GroupBy(不仅仅是它)的SQL翻译仍然不稳定。看起来我们必须等待3.0才能在这个领域获得改进。


1
基本上就是我找到的,感谢您的努力。 - andleer
@andleer 没有电流?上述代码目前是有效的。或者你指的是其他问题吗? - Ivan Stoev
好的,这个方法可行但它还相当笨拙。EF 的笨拙,而不是你的解决方案的问题。我担心 EF 中的某些变化会导致这个解决方案失效... 这样说可以吗?我将尝试编写一些原始 SQL 代码并看看我能得到什么。然后决定最佳行动方案。感谢您的帮助。 - andleer
同意。只是不要直接使用原始的 SQL 查询,我建议先创建、映射并使用数据库标量函数将日期时间转换为字符串键。 - Ivan Stoev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接