如何在EF Core中单次查询获取分组数量及总值?
EF Core实现单次查询获取分组计数与总值
先看数据表结构:
id internal_id external_id value --- ----------- ----------- ----- 1 1 null 5 2 1 null 3 3 null 2 8 4 null 2 3 5 3 null 2 6 null 4 9
需求是按(internal_id, external_id)分组,获取分组总数(此处为4)以及所有分组的value总和(此处为30),对应的PostgreSQL原生SQL用CTE实现如下:
WITH t AS ( SELECT sum(value) val FROM phones GROUP BY internal_id, external_id ) SELECT count(*), sum(val) FROM t;
你当前的做法是把所有分组的value总和拉到客户端再计算总数和总和,确实会浪费网络带宽,完全可以通过EF Core的Linq查询让数据库直接返回这两个结果,只需要一次查询:
var stats = await _Phones // 按目标字段分组,计算每个分组的value总和 .GroupBy(x => new { x.InternalId, x.ExternalId }) .Select(g => g.Sum(x => x.Value)) // 将每个分组的总和转为包含计数标识的结构 .Select(val => new { GroupCount = 1, GroupSum = val }) // 按固定值分组,实现全局聚合 .GroupBy(_ => 1) // 计算最终的分组总数和总value和 .Select(g => new { TotalGroupCount = g.Count(), TotalValueSum = g.Sum(x => x.GroupSum) }) .FirstOrDefaultAsync(); int groupCount = stats.TotalGroupCount; decimal totalValue = stats.TotalValueSum;
这段Linq查询会被EF Core转换为和你提供的CTE逻辑一致的SQL,所有计算都在数据库端完成,最终只返回两个数值,避免了传输大量中间数据。
如果更倾向于使用原生SQL(比如担心Linq的转换问题),也可以直接用FromSqlRaw执行你写的SQL语句:
// 注意:若使用无实体查询,需确保EF Core版本支持,或临时映射到实体字段 var stats = await _context.Database .SqlQuery<StatsResult>(@" WITH t AS ( SELECT sum(value) val FROM phones GROUP BY internal_id, external_id ) SELECT count(*) as TotalGroupCount, sum(val) as TotalValueSum FROM t; ") .FirstOrDefaultAsync(); // 需定义对应的结果类 public class StatsResult { public int TotalGroupCount { get; set; } public decimal TotalValueSum { get; set; } }
更推荐使用Linq写法,它能更好地适配EF Core的上下文和类型安全。
内容的提问来源于stack exchange,提问作者egeo
相关产品推荐
相关产品推荐

