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

重构LINQ查询并返回分组后的单个聚合结果

重构你的LINQ查询,返回单个聚合结果

首先我得先拆解一下你这段查询的核心意图:你想要筛选出IsValid为true、且CreatedOn落在[endDate, startDate)区间内的Application记录,然后计算这些记录的ApplicationTime和DecisionTime的平均值(四舍五入取整),最终返回包含这两个平均值的单个结果。

原代码的写法过于繁琐,而且用GroupBy((x) => (int)1)这种方式把所有数据归为一组,再用First取结果,其实完全可以简化。下面给你两种重构方案:

方案一:去掉不必要的分组(推荐)

既然你是对所有符合条件的数据计算整体平均值,根本不需要分组操作,直接对筛选后的序列计算聚合即可,代码简洁很多:

如果你使用的是EF Core等支持LINQ to Entities的ORM,还能让ORM帮你转换成高效的SQL聚合查询:

var result = r.Find<Application>(x => x.IsValid && x.CreatedOn < startDate && x.CreatedOn >= endDate)
              .GroupBy(x => 1) // 若不需要分组语义,这一行可以直接去掉,直接用下面的聚合逻辑
              .Select(g => new 
              { 
                  AvgApplicationTime = (int)Math.Round(g.Average(x => x.ApplicationTime)), 
                  AvgDecisionTime = (int)Math.Round(g.Average(x => x.DecisionTime)) 
              })
              .SingleOrDefault(); // 确保返回单个结果,无匹配数据时返回null

如果是内存中的集合操作,也可以用Aggregate手动计算,避免潜在的空序列异常:

var result = r.Find<Application>(x => x.IsValid && x.CreatedOn < startDate && x.CreatedOn >= endDate)
              .Select(x => new { x.ApplicationTime, x.DecisionTime })
              .Aggregate(
                  new { SumAppTime = 0, SumDecTime = 0, Count = 0 },
                  (acc, item) => new 
                  { 
                      SumAppTime = acc.SumAppTime + item.ApplicationTime, 
                      SumDecTime = acc.SumDecTime + item.DecisionTime, 
                      Count = acc.Count + 1 
                  },
                  acc => acc.Count == 0 
                      ? new { AvgApplicationTime = 0, AvgDecisionTime = 0 } // 无数据时返回默认值
                      : new 
                      { 
                          AvgApplicationTime = (int)Math.Round((double)acc.SumAppTime / acc.Count), 
                          AvgDecisionTime = (int)Math.Round((double)acc.SumDecTime / acc.Count) 
                      }
              );

方案二:简化原分组查询的写法

如果你坚持要保留分组逻辑(比如后续可能扩展分组维度),可以把原代码的冗余写法大幅简化,提升可读性:

// 先把筛选条件抽出来,让逻辑更清晰
Expression<Func<Application, bool>> filterCondition = x => 
    x.IsValid && x.CreatedOn < startDate && x.CreatedOn >= endDate;

var result = r.Find(filterCondition)
             .GroupBy(x => 1) // 简化分组键写法,不需要强制转换为(int)1
             .Select(g => new 
             { 
                 AvgApplicationTime = (int)Math.Round(g.Average(x => x.ApplicationTime)), 
                 AvgDecisionTime = (int)Math.Round(g.Average(x => x.DecisionTime)) 
             })
             .FirstOrDefault(); // 获取唯一分组结果,无数据时返回默认值

关键改进点:

  • 简化表达式结构:把嵌套的Queryable静态方法调用改成流畅的方法链,可读性提升明显
  • 去除冗余转换:GroupBy(x => 1)已经足够,不需要强制转(int)1
  • 明确处理边界情况:用SingleOrDefault或FirstOrDefault替代原代码的First,避免无匹配数据时抛出异常
  • 可选移除分组:如果不需要分组维度,直接计算聚合更高效,减少不必要的分组操作

内容的提问来源于stack exchange,提问作者John Ohara

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:17:39