如何在单个LINQ查询中同时获取总记录数与过滤后的结果集?
实现方案
可以在单次LINQ查询中完成需求,核心是使用恒定值分组的技巧,仅向数据库发送一次请求即可同时拿到无日期过滤的总匹配数,以及带日期过滤的结果集。
完整单次查询实现代码
// 提前计算日期阈值,避免LINQ翻译为SQL时出现不可优化的表达式 var dateThreshold = DateTime.Now.AddDays(-60); var result = await (from tA in ctx.TableA join tB in ctx.TableB on tA.Id equals tB.CustId where tA.Id == 12345 select new { tA, tB }) // 固定分组键,将所有匹配数据归入同一个分组 .GroupBy(_ => 1) .Select(g => new QueryResult { // 统计分组总条目,对应无日期过滤的总匹配数 TotalPossibleCount = g.LongCount(), // 分组内应用日期过滤,排序后投影为ResultObj Results = g.Where(x => x.tB.CreatedDate >= dateThreshold) .OrderByDescending(x => x.tB.CreatedDate) .Select(x => new ResultObj { // 原有属性赋值逻辑,通过x.tA、x.tB取值 }) .ToList() }) // 仅取唯一的分组结果 .FirstOrDefaultAsync(); // 兜底处理无匹配数据的场景 result ??= new QueryResult { TotalPossibleCount = 0, Results = new List<ResultObj>() }; return result;
实现说明
- 该写法会被EF Core翻译为带
COUNT(*) OVER()窗口函数的单条SQL语句,全程仅与数据库交互一次,不会产生多次查询开销 - 兼容EF Core 3.1及以上版本,旧版EF6需要调整写法适配
可选替代方案
如果对代码可读性要求更高,也可以选择两次独立异步查询的写法,仅多一次极轻量的数据库网络往返,绝大多数场景下性能差异可忽略:
var dateThreshold = DateTime.Now.AddDays(-60); // 无日期过滤的基础查询 var baseQuery = from tA in ctx.TableA join tB in ctx.TableB on tA.Id equals tB.CustId where tA.Id == 12345 select new { tA, tB }; // 第一次查询拿总匹配数 var totalCount = await baseQuery.LongCountAsync(); // 第二次查询拿过滤后的结果集 var results = await baseQuery .Where(x => x.tB.CreatedDate >= dateThreshold) .OrderByDescending(x => x.tB.CreatedDate) .Select(x => new ResultObj { // 原有属性赋值逻辑 }) .ToListAsync(); return new QueryResult { TotalPossibleCount = totalCount, Results = results };
内容的提问来源于stack exchange,提问作者SlappingTheBass12
相关产品推荐
相关产品推荐

