EF Core 的聚合查询本质是把计算逻辑下推到数据库执行,而不是在内存里遍历。用对方法,才能既准确又高效。
常用聚合方法怎么写
直接调用 Count()、Sum()、Avg() 等扩展方法,它们会生成 SQL 的对应聚合函数:
Count():统计行数,context.Orders.Count()→
SELECT COUNT(*) FROM OrdersCount(x => x.Status == "Shipped"):带条件计数,生成
COUNT(CASE WHEN ... THEN 1 END)Sum(x => x.Amount):只支持数值类型字段,null 值自动忽略 Avg(x => x.Rating):同理,字段为 null 的记录不参与计算 Max(x => x.CreatedAt) 或 Min(x => x.Price):支持日期、数字、字符串(按字典序)
分组后聚合更实用
单表聚合往往不够,多数业务需要“按某维度分组再算总数/平均值”。EF Core 支持链式 GroupBy + Select:
context.Orders.GroupBy(o => o.CustomerId).Select(g => new { Id = g.Key, Total = g.Sum(o => o.Amount) })
结果是 IQueryable,仍走数据库,不会把全部订单拉到内存
可嵌套多个聚合:g.Average(o => o.Quantity)、
g.Count()同时用
注意 null 和类型陷阱
聚合行为和数据库一致,但容易踩坑:
Count(x => x.Name) 统计的是Name IS NOT NULL的行数,不是总行数 Sum() 和 Avg() 遇到非数值类型字段(比如 string),运行时报错或返回 0(取决于 provider) Max()/Min() 对字符串字段,按字母顺序比较,不是按长度 想统计所有行(含 null),用 Count() 不带参数;想统计某列非空行,才传表达式
避免常见性能错误
聚合必须保持在服务端执行,否则失去意义:
❌ 错误:先.ToList()再
.Sum()→ 全量查出再内存计算 ✅ 正确:所有聚合操作前不触发枚举,保持
IQueryable状态 调试时可用
context.Orders.ToQueryString()(EF Core 7+)看生成的 SQL
基本上就这些。写对表达式,看清字段类型,让数据库干活,别自己搬数据。
