在C#开发的实际业务场景中,分页应用是处理大量数据展示的必备功能,合理的分页实现既能减少单次数据查询的压力,也能提升用户查看数据的体验。分页的核心逻辑是根据当前页码和每页条数,计算出需要查询的数据范围,再从数据源中获取对应数据。

分页核心参数定义
构建分页应用首先需要明确分页相关的核心参数,这些参数会贯穿整个分页逻辑的实现过程,常见的参数包括当前页码、每页显示条数、总数据量、总页数。
- 当前页码(pageIndex):用户当前查看的页码,通常从1开始计数
- 每页条数(pageSize):每一页展示的数据条数,可根据业务需求设置固定值或允许用户自定义
- 总数据量(totalCount):符合查询条件的所有数据的总条数,用于计算总页数
- 总页数(totalPage):根据总数据量和每页条数计算得出的总页码数
分页逻辑计算方法
分页逻辑的核心是计算总页数和查询数据的起始偏移量,下面是C#中实现分页参数计算的通用方法。
// 分页参数计算类
public class PaginationHelper
{
/// <summary>
/// 计算总页数
/// </summary>
/// <param name="totalCount">总数据量</param>
/// <param name="pageSize">每页条数</param>
/// <returns>总页数</returns>
public static int CalculateTotalPage(int totalCount, int pageSize)
{
if (pageSize <= 0)
{
pageSize = 10; // 默认每页10条
}
// 向上取整计算总页数
return (int)Math.Ceiling((double)totalCount / pageSize);
}
/// <summary>
/// 计算查询数据的起始偏移量
/// </summary>
/// <param name="pageIndex">当前页码</param>
/// <param name="pageSize">每页条数</param>
/// <returns>数据起始偏移量</returns>
public static int CalculateOffset(int pageIndex, int pageSize)
{
if (pageIndex < 1)
{
pageIndex = 1; // 页码最小为1
}
return (pageIndex - 1) * pageSize;
}
}
结合数据库查询实现分页
实际开发中分页通常需要和数据库查询结合,下面以SQL Server数据库为例,展示如何在C#中实现带分页的数据查询,使用EF Core作为ORM框架。
数据模型定义
首先定义需要查询的数据实体类,这里假设查询的是用户信息表。
// 用户实体类
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public DateTime CreateTime { get; set; }
}
分页查询实现
下面是完整的分页查询方法,包含参数校验、总数据量查询、分页数据查询和结果封装。
// 分页查询结果封装类
public class PagedResult<T>
{
public int PageIndex { get; set; } // 当前页码
public int PageSize { get; set; } // 每页条数
public int TotalCount { get; set; } // 总数据量
public int TotalPage { get; set; } // 总页数
public List<T> Data { get; set; } // 当前页数据
}
// 分页查询服务类
public class UserService
{
private readonly AppDbContext _dbContext;
public UserService(AppDbContext dbContext)
{
_dbContext = dbContext;
}
/// <summary>
/// 获取分页用户数据
/// </summary>
/// <param name="pageIndex">当前页码</param>
/// <param name="pageSize">每页条数</param>
/// <returns>分页结果</returns>
public async Task<PagedResult<User>> GetPagedUsersAsync(int pageIndex, int pageSize)
{
// 参数校验
if (pageIndex < 1)
{
pageIndex = 1;
}
if (pageSize < 1)
{
pageSize = 10;
}
// 查询总数据量
int totalCount = await _dbContext.Users.CountAsync();
// 计算总页数
int totalPage = PaginationHelper.CalculateTotalPage(totalCount, pageSize);
// 计算起始偏移量
int offset = PaginationHelper.CalculateOffset(pageIndex, pageSize);
// 查询分页数据,按创建时间倒序排列
List<User> data = await _dbContext.Users
.OrderByDescending(u => u.CreateTime)
.Skip(offset)
.Take(pageSize)
.ToListAsync();
// 封装分页结果
return new PagedResult<User>
{
PageIndex = pageIndex,
PageSize = pageSize,
TotalCount = totalCount,
TotalPage = totalPage,
Data = data
};
}
}
前端调用示例
如果是Web API场景,前端可以通过接口传入分页参数获取分页数据,下面是接口调用的示例代码。
// Web API控制器中的接口方法
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly UserService _userService;
public UserController(UserService userService)
{
_userService = userService;
}
[HttpGet("paged")]
public async Task<IActionResult> GetPagedUsers([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 10)
{
PagedResult<User> result = await _userService.GetPagedUsersAsync(pageIndex, pageSize);
return Ok(result);
}
}
分页实现的注意事项
在构建分页应用时,还需要注意以下几个常见问题,避免出现逻辑错误:
- 页码参数需要做边界处理,当pageIndex小于1时自动设置为1,当pageIndex大于总页数时可以返回空数据或者自动设置为最后一页
- 每页条数需要设置最大值限制,避免用户传入过大的pageSize导致查询压力过大
- 如果查询条件较多,总数据量的查询需要和数据查询的条件保持一致,否则会出现总页数和实际数据不匹配的问题
- 对于数据量特别大的表,分页查询时尽量使用索引覆盖的排序字段,避免查询性能下降
分页功能的核心是保证参数计算准确,同时兼顾查询性能,以上实例方法可以直接复用在实际项目中,也可以根据具体的业务需求做对应的调整。