如何修改GetAll函数实现ServerNames数据的服务端分页?
服务端分页实现方案(基于.NET Core 7 Blazor + EF Core)
1. 调整服务层方法定义
首先修改GetAll方法的参数与返回类型,接收分页核心参数(页码、页大小),并返回包含分页元数据的结果对象(假设你已定义PagedResult<T>分页模型):
// 分页结果模型(如果未定义可直接使用) public class PagedResult<T> { public List<T> Items { get; set; } = new(); public int TotalCount { get; set; } public int PageIndex { get; set; } public int PageSize { get; set; } public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize); } // 定义DTO用于返回关联后的数据(避免直接暴露实体) public class ServerNameWithTypeDto { public int Id { get; set; } public string ServerName { get; set; } public string ServerTypeName { get; set; } // 按需添加其他字段 }
2. 实现关联查询的服务端分页
修改GetAll方法,基于EF Core的IQueryable实现真正的服务端分页(而非内存分页),结合你的分页扩展类完成逻辑:
public async Task<PagedResult<ServerNameWithTypeDto>> GetAll(int pageIndex, int pageSize) { // 构建关联查询的IQueryable(延迟执行,未触发数据库查询) var query = _context.ServerNames .Include(s => s.ServerType) // 关联ServerType表 .Select(s => new ServerNameWithTypeDto { Id = s.Id, ServerName = s.Name, ServerTypeName = s.ServerType.TypeName // 映射其他需要的字段 }); // 调用你的分页扩展类完成分页逻辑 return await query.PaginateAsync(pageIndex, pageSize); }
如果你的分页扩展类未封装总条数查询,可手动实现:
public static async Task<PagedResult<T>> PaginateAsync<T>(this IQueryable<T> query, int pageIndex, int pageSize) { var totalCount = await query.CountAsync(); var items = await query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync(); return new PagedResult<T> { Items = items, TotalCount = totalCount, PageIndex = pageIndex, PageSize = pageSize }; }
3. 分页参数校验(可选但推荐)
在方法内添加参数合法性校验,避免无效请求:
public async Task<PagedResult<ServerNameWithTypeDto>> GetAll(int pageIndex, int pageSize) { // 参数校验 pageIndex = Math.Max(1, pageIndex); pageSize = Math.Clamp(pageSize, 1, 100); // 限制最大页大小,防止一次性加载过多数据 // 后续查询逻辑... }
4. Blazor组件端调用示例
在Blazor组件中调用分页接口,实现分页控件交互:
@page "/server-list" @inject IServerNameService ServerNameService <h3>服务器列表</h3> <!-- 分页控件 --> <div class="pagination-controls"> <span>总条数: @_pagedResult.TotalCount | 总页数: @_pagedResult.TotalPages | 当前页: @_pagedResult.PageIndex</span> <button disabled="@(_pagedResult.PageIndex <= 1)" @onclick="() => LoadPage(_pagedResult.PageIndex - 1)">上一页</button> <button disabled="@(_pagedResult.PageIndex >= _pagedResult.TotalPages)" @onclick="() => LoadPage(_pagedResult.PageIndex + 1)">下一页</button> </div> <!-- 数据表格 --> <table class="table"> <thead> <tr> <th>ID</th> <th>服务器名称</th> <th>服务器类型</th> </tr> </thead> <tbody> @foreach (var server in _pagedResult.Items) { <tr> <td>@server.Id</td> <td>@server.ServerName</td> <td>@server.ServerTypeName</td> </tr> } </tbody> </table> @code { private PagedResult<ServerNameWithTypeDto> _pagedResult = new(); private const int DefaultPageSize = 10; protected override async Task OnInitializedAsync() { await LoadPage(1); } private async Task LoadPage(int pageIndex) { _pagedResult = await ServerNameService.GetAll(pageIndex, DefaultPageSize); StateHasChanged(); } }
关键注意事项
- 必须使用
IQueryable:确保EF Core能将Skip/Take逻辑翻译成SQL语句,实现真正的服务端分页,避免先加载全量数据到内存再分页的性能问题。 - 避免提前触发查询:不要在分页前调用
ToListAsync等方法,否则会转为内存分页。 - 投影优先于Include:如果只需要部分字段,使用
Select投影比Include更高效,EF会自动生成精简的关联查询SQL。
内容的提问来源于stack exchange,提问作者ahmed abdelaziz
相关产品推荐
相关产品推荐

