You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF中GroupBy()未按预期工作,仅内存分组才生效

LINQ分组查询结果异常问题排查与解决

我编写了如下LINQ查询,期望按年月分组得到多条统计结果,但实际仅返回1条:

var results = await DbContext.Trucks
    .Where(t => t.Departure.HasValue)
    .Select(t => new
    {
        t.Departure!.Value.Year,
        t.Departure!.Value.Month,
        Quantity = t.InboundQuantity + t.ToTransfers.Sum(x => x.Quantity) - t.FromTransfers.Sum(x => x.Quantity)
    })
    .GroupBy(t => new { t.Year, t.Month })
    .ToDictionaryAsync(g => new DateTime(g.Key.Year, g.Key.Month, 1), g => g.Sum(x => x.Quantity));

执行结果:

results Count = 1
+ [0]   {[{7/1/2021 12:00:00 AM}, 3842405714]}

但如果先通过ToList()将所有数据加载到内存,再执行分组逻辑,就能得到预期的27条结果:

var test = DbContext.Trucks
    .Where(t => t.Departure.HasValue)
    .Select(t => new
    {
        t.Departure!.Value.Year,
        t.Departure!.Value.Month,
        Quantity = t.InboundQuantity + t.ToTransfers.Sum(x => x.Quantity) - t.FromTransfers.Sum(x => x.Quantity)
    })
    .ToList();

var test2 = test
    .GroupBy(t => new { t.Year, t.Month })
    .ToDictionary(g => new DateTime(g.Key.Year, g.Key.Month, 1), g => g.Sum(x => x.Quantity));

执行结果:

test2   Count = 27
+ [0]   {[{1/1/2022 12:00:00 AM}, 95309170]}
+ [1]   {[{2/1/2022 12:00:00 AM}, 79737674]}
+ [2]   {[{3/1/2022 12:00:00 AM}, 173875538]}
+ [3]   {[{7/1/2021 12:00:00 AM}, 125219196]}
+ [4]   {[{8/1/2021 12:00:00 AM}, 110993954]}
+ [5]   {[{10/1/2021 12:00:00 AM}, 129282632]}
+ [6]   {[{11/1/2021 12:00:00 AM}, 160927222]}
+ [7]   {[{12/1/2021 12:00:00 AM}, 117813444]}
+ [8]   {[{9/1/2021 12:00:00 AM}, 26260420]}
+ [9]   {[{4/1/2022 12:00:00 AM}, 161695966]}
+ [10]  {[{5/1/2022 12:00:00 AM}, 184781001]}
+ [11]  {[{6/1/2022 12:00:00 AM}, 146985217]}
+ [12]  {[{7/1/2022 12:00:00 AM}, 84260160]}
+ [13]  {[{8/1/2022 12:00:00 AM}, 89769875]}
+ [14]  {[{10/1/2022 12:00:00 AM}, 187958697]}
+ [15]  {[{11/1/2022 12:00:00 AM}, 175034225]}
+ [16]  {[{9/1/2022 12:00:00 AM}, 108421771]}
+ [17]  {[{1/1/2023 12:00:00 AM}, 179720773]}
+ [18]  {[{12/1/2022 12:00:00 AM}, 110000415]}
+ [19]  {[{2/1/2023 12:00:00 AM}, 210461751]}
+ [20]  {[{3/1/2023 12:00:00 AM}, 232239876]}
+ [21]  {[{4/1/2023 12:00:00 AM}, 176482465]}
+ [22]  {[{5/1/2023 12:00:00 AM}, 218732769]}
+ [23]  {[{6/1/2023 12:00:00 AM}, 186324324]}
+ [24]  {[{7/1/2023 12:00:00 AM}, 151700649]}
+ [25]  {[{8/1/2023 12:00:00 AM}, 142653374]}
+ [26]  {[{9/1/2023 12:00:00 AM}, 75763156]}

问题原因

这是因为EF Core的GroupBy与LINQ to Objects的GroupBy行为存在差异:

  • 直接在EF中执行GroupBy时,查询会被翻译成SQL在数据库层面执行。原查询的Select阶段已经对每条Truck计算了包含关联集合Sum的Quantity,但EF在翻译GroupBy+Sum的组合逻辑时,错误地将整个数据集的Quantity做了全局汇总,而非按Year和Month分组聚合。
  • 先通过ToList加载到内存后,使用的是LINQ to Objects的GroupBy,它会严格按照内存中的数据分组,再对每组的Quantity求和,因此能得到正确结果。

正确写法

通过指定GroupBy的第二个参数(元素选择器),明确告诉EF分组后要聚合的是Quantity字段,即可让EF生成正确的分组聚合SQL:

var results = await DbContext.Trucks
    .Where(t => t.Departure.HasValue)
    .Select(t => new
    {
        t.Departure!.Value.Year,
        t.Departure!.Value.Month,
        Quantity = t.InboundQuantity + t.ToTransfers.Sum(x => x.Quantity) - t.FromTransfers.Sum(x => x.Quantity)
    })
    .GroupBy(t => new { t.Year, t.Month }, x => x.Quantity)
    .ToDictionaryAsync(g => new DateTime(g.Key.Year, g.Key.Month, 1), g => g.Sum());

内容的提问来源于stack exchange,提问作者Jonathan Wood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:45:16