EF Core 3.1查询各MemberId最新修改行报错问题
错误原因
- 第一种
Include写法报错:EF Core 3.1的Include仅支持直接映射导航属性,不允许在Include的lambda表达式内对导航集合做排序、截取、筛选操作。你写的m => m.Histories.OrderByDescending(h => h.LastModifiedDate).FirstOrDefault()属于在Include内部附加了查询逻辑,不符合该版本的语法约束,因此触发Lambda expression used inside Include is not valid错误。 - 第二种GroupBy写法报错:EF Core 3.1对GroupBy的SQL翻译支持非常有限,不支持“分组后对组内元素排序再取第一条”的逻辑翻译,引擎无法把这段LINQ转换成对应SQL语句,因此抛出翻译失败异常。
可用实现方案
方案1:服务端可翻译写法(推荐,无全表加载性能问题)
通过子查询匹配每个MemberId对应的最新修改时间,EF Core 3.1可正常将该写法翻译为高效SQL:
var latestRecords = context.Histories .Where(h => h.LastModifiedDate == context.Histories .Where(sub => sub.MemberId == h.MemberId) .Max(sub => sub.LastModifiedDate)) .ToList();
注意:如果同一个MemberId下存在多条LastModifiedDate完全相同的记录,该写法会返回所有匹配记录。如果业务上要求一个MemberId只返回一条,可以给LastModifiedDate设置更高精度,或者在查询后做内存去重。
方案2:客户端执行写法(适合小数据量场景)
如果Histories表数据量很小,可以先调用AsEnumerable()切换到内存LINQ执行,后续的分组排序取首条逻辑就不会触发SQL翻译错误:
var latestRecords = context.Histories .AsEnumerable() .GroupBy(h => h.MemberId) .Select(g => g.OrderByDescending(h => h.LastModifiedDate).First()) .ToList();
风险提示:该写法会把Histories表全量数据加载到应用内存,数据量过大会导致接口响应慢、内存占用过高,大表场景禁止使用。
方案3:版本升级方案
如果可以升级EF Core到5.0及以上版本,上述两种原始写法大部分场景都可被正常翻译,同时高版本新增了过滤包含(Filtered Include)能力,支持在Include中直接对导航集合做排序、筛选,写法更简洁。
内容的提问来源于stack exchange,提问作者user989988
相关产品推荐
相关产品推荐

