ef core 6.0及以上版本支持在linq查询中直接使用 distinctby(),它会将其翻译为 sql 的 distinct 或窗口函数(如 row_number()),从而在数据库端完成去重。对于低版本,需先使用 groupby 再取首项,或在内存中使用 linq to objects 的 distinctby。

EF Core 6+ 如何将 DistinctBy 翻译成 SQL
当使用 EF Core 6.0 或更高版本时,直接调用 DistinctBy 会被 Provider 识别并转换为高效的 SQL 查询。例如,根据 Name 字段去重,底层通常生成带有 ROW_NUMBER() OVER (PARTITION BY ...) 的逻辑,确保只返回每组的第一条记录。

using var ctx = new AppContext();
var result = await ctx.Users
.OrderBy(u => u.Id)
.DistinctBy(u => u.Name)
.ToListAsync();
// 预期结果: 按Id排序后,Name重复的记录只保留第一条
低版本 EF Core 如何实现等效去重
在 EF Core 3.1 或更低版本中,DistinctBy 无法被翻译。此时必须使用 GroupBy 结合 FirstOrDefault 来实现相同逻辑。这种方式同样会在数据库端执行分组和选取操作,避免将全量数据拉到内存中去重。

using var ctx = new AppContext();
var result = await ctx.Users
.GroupBy(u => u.Name)
.Select(g => g.OrderBy(u => u.Id).FirstOrDefault())
.ToListAsync();
// 预期结果: 与EF Core 6+的DistinctBy行为一致
DistinctBy 在内存中的具体表现
如果查询未使用 AsNoTracking() 或未限制数量,EF Core 可能会将部分数据加载到内存中。此时若对已跟踪实体调用 DistinctBy,它实际上是在内存中运行 LINQ to Objects 版本,而非 SQL 翻译。这会导致性能下降,因为所有候选记录都会被拉取。


















