You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用EF Core在单查询中同时获取分页数据与总条数?

解决EF Core中单查询同时获取分页数据与总结果数的问题

你当前的LINQ写法会触发两次查询,原因是Select中调用的Count()会被EF Core解析为独立的聚合查询,而非窗口函数。要实现和你手动编写的MySQL语句一致的单查询效果,可通过以下两种方式解决:

方法一:使用EF Core内置的窗口函数支持(推荐)

EF Core 5.0及以上版本支持通过EF.Functions.CountOver()映射SQL的窗口函数,直接生成包含COUNT(*) OVER ()的单查询:

// 构建筛选查询
var filterQuery = dbContext.Users.Where(u => u.Name.Contains("John"));

// 投影包含窗口函数计算的总条数,再执行分页
var queryResult = filterQuery
    .Select(u => new 
    {
        User = u,
        TotalCount = EF.Functions.CountOver()
    })
    .OrderBy(item => item.User.Name)
    .Skip(0)
    .Take(30)
    .ToList();

// 提取总条数(所有结果的TotalCount值相同,取第一个即可)
int totalCount = queryResult.FirstOrDefault()?.TotalCount ?? 0;
// 提取当前页的数据
var pageData = queryResult.Select(item => item.User).ToList();

此写法会生成与你手动编写一致的SQL:

SELECT 
    u.*,
    COUNT(*) OVER () AS `TotalCount`
FROM
    `Users` AS `u`
WHERE
    `u`.`Name` LIKE '%John%'
ORDER BY
    `u`.`Name`
LIMIT 30 OFFSET 0

方法二:直接执行原生SQL(兼容低版本EF Core)

如果你的EF Core版本低于5.0,可通过FromSqlRaw直接执行手动编写的MySQL语句,需要注意接收结果的实体或DTO需包含TotalCount字段:

int pageSize = 30;
int offset = 0;
string searchKeyword = "%John%";

// 假设存在包含TotalCount的DTO类:UserWithTotalCount
var result = dbContext.Set<UserWithTotalCount>().FromSqlRaw(@"
    SELECT 
        u.*,
        COUNT(*) OVER () AS TotalCount
    FROM
        Users u
    WHERE
        u.Name LIKE {0}
    ORDER BY
        u.Name
    LIMIT {1}, {2}", searchKeyword, offset, pageSize)
    .ToList();

int totalCount = result.FirstOrDefault()?.TotalCount ?? 0;
var pageData = result.Select(item => new User 
{
    Id = item.Id,
    Name = item.Name
    // 映射其他字段
}).ToList();

关键说明

  • 避免在Select中直接调用Count():这种写法会让EF Core优先执行聚合查询获取总条数,再执行分页查询,导致两次数据库交互。
  • 窗口函数的优势:单查询即可同时获取分页数据和总条数,减少数据库往返次数,提升性能。

内容的提问来源于stack exchange,提问作者Mensur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 09:04:54