EF Core GroupBy怎么用 EF Core分组查询教程

来源:这里教程网 时间:2026-02-21 17:37:02 作者:

ef core groupby怎么用 ef core分组查询教程

EF Core 的

GroupBy
本质是把数据库的
GROUP BY
操作翻译成 LINQ 表达式,关键不是“怎么写”,而是“怎么写才能让 EF 正确生成 SQL 并高效执行”。用错顺序或结构,容易触发客户端分组(即先查全量再内存分组),性能会断崖式下跌。

单字段分组 + 聚合统计

最常用场景:按某个字段分组,算每组数量、总和、平均值等。必须确保

GroupBy
后紧跟
Select
,且只引用
g.Key
和聚合函数(
Count()
Sum()
Average()
等)。

正确写法(数据库端执行):
db.Consumers.GroupBy(c => c.Gender).Select(g => new { Gender = g.Key, Count = g.Count() }).ToList();
错误写法(先加载全部到内存再分组):
db.Consumers.ToList().GroupBy(...)
—— 绝对避免
生成的 SQL 是标准
SELECT COUNT(*) ... GROUP BY [Gender]
,不走内存

多字段分组(组合键)

需要按多个列联合分组时,用匿名对象或元组作 Key。注意 Key 中的字段名要和

Select
中的
g.Key.Xxx
严格对应。

推荐写法(匿名对象):
db.OrderItems.GroupBy(x => new { x.Currency, x.Status }).Select(g => new { Currency = g.Key.Currency, Status = g.Key.Status, Total = g.Sum(o => o.Amount), Count = g.Count() });
也可用 ValueTuple:
.GroupBy(x => (x.Currency, x.Status))
,Key 访问改为
g.Key.Item1
/
g.Key.Item2
生成 SQL 会包含
GROUP BY [Currency], [Status]

分组后取每组第一条(如最新记录)

这不是纯聚合,但很常见——比如“每个用户最近一次登录日志”。EF Core 8+ 支持

Aggregate
或子查询方式,但最稳妥的是用
ROW_NUMBER()
思路,不过直接写 LINQ 更简洁:

典型写法:
db.LoginLogs.GroupBy(x => x.UserId).Select(g => g.OrderByDescending(x => x.DateAdded).First());
EF Core 7+ 会将其翻译为带
ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)
的 SQL,不拉全量数据
注意:不能在
Select
外再调用
First()
,必须嵌套在
Select
内部

映射到自定义 DTO 或实体类

别硬塞匿名类型,尤其在 API 返回或复用逻辑中。建议定义明确的 DTO 类,并在

Select
中构造它:

定义类:
public class CaseSummary { public string YourKey { get; set; } public int TotalCases { get; set; } public int TotalFlagCases { get; set; } }
查询中使用:
.Select(g => new CaseSummary { YourKey = g.Key, TotalCases = g.Count(), TotalFlagCases = g.Sum(x => x.Flag ? 1 : 0) })
这样既类型安全,又方便序列化和单元测试

基本上就这些。核心就一条:GroupBy 必须在 Select 前,聚合必须在 Select 内,所有字段都得能被 EF 翻译成 SQL。写完可以开 SQL Profiler 看一眼生成的语句,心里就有底了。

相关推荐