.NET Core3.1+EF5.0.9下无需AsEnumerable的可翻译GroupBy查询方案问询
问题根因
EF Core 3.0及以上版本默认关闭了隐式客户端评估,你原有写法中GroupBy后取First()的操作无法直接翻译成SQL(SQL标准中的GROUP BY仅支持聚合操作,不支持直接取分组内首条记录),才会触发报错。
替代写法(无需加AsEnumerable)
场景1:仅需统计分组数量(匹配你当前示例的最终Count()需求)
你给出的示例代码本质是统计符合条件的记录中,不同SM_PROVIDER_ID的去重计数,完全可以简化为以下写法,全程可被EF 5翻译为SQL执行:
var count = unitOfWork.GetRepository<MAPPING_TABLE>() .GetAll(predicate: x => x.USER_ID == userId) .Select(x => x.Site.SM_PROVIDER_ID) .Distinct() .Count();
这种写法不需要加载任何关联导航属性,执行效率远高于原有全量加载实体到内存分组的方案。
场景2:需要获取每个分组首条的完整实体数据
如果你需要返回每个SM_PROVIDER_ID对应的首条完整记录(包含你示例中Include的所有导航属性),可以借助EF 5支持翻译的RowNumber窗口函数实现:
// 获取每个分组首条实体的查询 var entityQuery = unitOfWork.GetRepository<MAPPING_TABLE>() .GetAll(predicate: x => x.USER_ID == userId) .Include(p => p.Site).ThenInclude(p => p.Provier).ThenInclude(p => p.Location) .AsNoTracking() .Select(x => new { Entity = x, // 按SM_PROVIDER_ID分区,可自定义排序规则决定哪条是首条 RowNum = EF.Functions.RowNumber<int>( partitionBy: x.Site.SM_PROVIDER_ID, ordering: x => x.Id) }) .Where(x => x.RowNum == 1) .Select(x => x.Entity); // 计数直接调用Count() var count = entityQuery.Count(); // 取实体列表调用ToList() var entityList = entityQuery.ToList();
注意事项
- 上述两种写法均全程在数据库侧执行,不需要客户端内存分组,数据量较大时性能优势会非常明显。
- 窗口函数写法中的排序规则可根据你的实际业务需求调整,比如按创建时间倒序取最新的一条记录。
内容的提问来源于stack exchange,提问作者Paritosh
相关产品推荐
相关产品推荐

