EF Core 5使用GroupBy取分组最新行遇无法翻译异常如何解决
EF Core 5 分组取最新行可翻译查询写法
EF Core 5 不支持直接对GroupBy返回的分组集合执行内部排序、取元素操作的SQL翻译,你可以改用窗口函数ROW_NUMBER的思路实现需求,该写法可完全被翻译为SQL在数据库端执行,无客户端评估性能损耗:
var entries = await _dbContext.MyTable .Select(s => new { Entity = s, RowNumber = EF.Functions.RowNumber() .Over(partition => partition .PartitionBy(s => s.Something) .OrderByDescending(s => s.CreatedDate)) }) .Where(s => s.RowNumber == 1) .Select(s => s.Entity) .ToListAsync();
注意事项
- 上述写法生成的SQL等价于原生SQL:
性能和手写原生SQL完全一致。SELECT * FROM ( SELECT *, ROW_NUMBER() OVER(PARTITION BY Something ORDER BY CreatedDate DESC) AS rn FROM MyTable ) t WHERE rn = 1 - 如果同一分组内存在多条
CreatedDate完全相同的记录,该写法只会返回其中一条,和你原写法的First()语义完全匹配。
兼容低版本EF Core可选方案
如果需要适配不支持窗口函数翻译的更低版本EF Core,可使用先查分组最大时间再关联的写法:
// 先查询每个分组的最大创建时间 var groupMaxDateQuery = _dbContext.MyTable .GroupBy(s => s.Something) .Select(g => new { GroupKey = g.Key, MaxDate = g.Max(s => s.CreatedDate) }); // 关联原表取对应记录 var entries = await _dbContext.MyTable .Join(groupMaxDateQuery, original => new { original.Something, original.CreatedDate }, group => new { Something = group.GroupKey, CreatedDate = group.MaxDate }, (original, group) => original) .ToListAsync();
该方案如果同一分组内存在多条时间等于最大值的记录,会全部返回,和
First()语义有差异,需要根据业务场景选择使用。
内容的提问来源于stack exchange,提问作者Milos
相关产品推荐
相关产品推荐

