如何为Web API实现分页限制单次调用返回结果?
实现Web API的分页功能(基于size和offset参数)
问题背景
搭建的基础Web API查询数据库时返回80万条数据,需要实现分页机制:通过size(每次返回条数)和offset(偏移量)参数控制每次API调用最多返回5000条数据,同时支持和其他筛选条件组合使用。
现有API调用示例:
localhost2343/api/dataset/data?First_Name=Dave localhost2343/api/dataset/data?Last_Name=Dave&First_Name=Ram localhost2343/api/dataset/data?size=1&offset=50 localhost2343/api/dataset/data?First_Name=Dave&size=1&offset=50
现有API代码:
[Route("data")] [HttpGet] public async Task<IQueryable<My_Model>> Get(My_Model? filter) { IQueryable<My_Model> Query = (from x in _context.My_DbSet select x); // 添加筛选条件 if (filter.Id != 0) { Query = Query.Where(x => x.Id == filter.Id); } if (!string.IsNullOrEmpty(filter.First_Name)) { Query = Query.Where(x => x.First_Name == filter.First_Name); } ... return Query; }
自行尝试的分页写法:
Query = Query.Skip((offset - 1) * size).Take(size);
解决方案
1. 调整参数接收与分页逻辑
直接在Get方法中新增size和offset参数,ASP.NET Core会自动绑定URL中的参数,无需关心参数顺序。同时完善分页逻辑:
[Route("data")] [HttpGet] public async Task<IQueryable<My_Model>> Get(My_Model? filter, int? size, int? offset) { // 原有筛选逻辑保持不变 IQueryable<My_Model> Query = (from x in _context.My_DbSet select x); if (filter.Id != 0) { Query = Query.Where(x => x.Id == filter.Id); } if (!string.IsNullOrEmpty(filter.First_Name)) { Query = Query.Where(x => x.First_Name == filter.First_Name); } ... // 分页逻辑处理 // 设置默认值:默认每次返回5000条,从第1页(offset=1)开始 int pageSize = size ?? 5000; // 强制限制最大条数,避免单次请求数据量过大 pageSize = Math.Min(pageSize, 5000); int pageOffset = offset ?? 1; // 你的尝试写法是正确的(offset从1开始计数) Query = Query.Skip((pageOffset - 1) * pageSize).Take(pageSize); return Query; }
2. 关键细节说明
- 参数绑定:URL中
size/offset和筛选条件的顺序不影响绑定,比如?First_Name=Dave&size=100&offset=3或?offset=2&size=500&Last_Name=Ram都能正常工作。 - 默认值与边界控制:未传递参数时默认返回5000条,同时限制最大返回条数为5000,防止恶意请求拖垮服务。
- 分页计数规则:当前写法中
offset从1开始(比如offset=50代表第50页),若需要offset从0开始计数(代表跳过前N条),则修改为Query.Skip(pageOffset * pageSize).Take(pageSize)即可。 - 性能保障:返回
IQueryable时,EF Core会将分页逻辑转换为SQL的OFFSET ... FETCH NEXT ...语句,不会一次性加载80万条数据到内存,保证查询性能。
3. 可选优化:返回总条数
如果需要前端计算总页数,可以封装返回对象,包含分页数据和总条数:
public class PagedResult<T> { public List<T> Data { get; set; } public int TotalCount { get; set; } } // 修改API方法 public async Task<PagedResult<My_Model>> Get(My_Model? filter, int? size, int? offset) { IQueryable<My_Model> Query = _context.My_DbSet; // 筛选逻辑... int totalCount = await Query.CountAsync(); // 分页逻辑... var data = await Query.Skip((pageOffset - 1) * pageSize).Take(pageSize).ToListAsync(); return new PagedResult<My_Model> { Data = data, TotalCount = totalCount }; }
内容的提问来源于stack exchange,提问作者dave
相关产品推荐
相关产品推荐

