ASP.NET Core 1.1中如何结合ViewModel使用PagingList<T>.CreateAsync()?
解决ASP.NET Core 1.1中多表查询ViewModel分页的IQueryable转换错误
这个问题我之前也碰到过,核心原因是PagingList<T>.CreateAsync要求传入的IQueryable必须是有序的(IOrderedQueryable)——分页需要稳定的结果顺序,否则不同页码返回的数据可能会混乱甚至重复。另外你当前的代码还有可以优化的地方,我来一步步帮你解决:
错误原因拆解
你现在的代码里,先把多表查询的结果全部加载到内存(遍历转成List<BookListViewModel>),再转成IQueryable传给分页方法。一来失去了EF Core延迟加载/按需查询的性能优势,二来这个内存中的IQueryable没有任何排序规则,不符合PagingList的要求,所以才会抛出“无法转换为IOrderedQueryable”的错误。
优化后的解决方案
1. 直接在LINQ查询中投影到ViewModel
不需要先查匿名类型再遍历转换,直接在EF查询里生成BookListViewModel,让EF只查询你需要的字段,提升性能:
var query = from b in _context.books join a in _context.authors on b.AuthorID equals a.AuthorId join bg in _context.bookgroups on b.BookGroupID equals bg.BookGroupId select new BookListViewModel { BookId = b.BookId, BookName = b.BookName, BookImage = b.BookImage, BookPageCount = b.BookPageCount, AuthorId = b.AuthorID, BookGroupId = b.BookGroupID, AuthorName = a.AuthorName, BookGroupName = bg.BookGroupName };
2. 给查询添加排序规则
给上面的查询加上排序,比如按BookId升序,这样查询就会变成IOrderedQueryable,满足PagingList的要求:
var orderedQuery = query.OrderBy(b => b.BookId);
3. 直接传入有序查询到分页方法
现在可以直接把这个有序的IOrderedQueryable传给PagingList.CreateAsync,不需要先转成List:
int pageSize = 3; int pageNumber = (page ?? 1); var pagedData = await PagingList<BookListViewModel>.CreateAsync(orderedQuery, pageNumber, pageSize);
完整修改后的Action代码
[HttpGet] public async Task<IActionResult> Index(int? page) { var query = from b in _context.books join a in _context.authors on b.AuthorID equals a.AuthorId join bg in _context.bookgroups on b.BookGroupID equals bg.BookGroupId select new BookListViewModel { BookId = b.BookId, BookName = b.BookName, BookImage = b.BookImage, BookPageCount = b.BookPageCount, AuthorId = b.AuthorID, BookGroupId = b.BookGroupID, AuthorName = a.AuthorName, BookGroupName = bg.BookGroupName }; // 添加排序,转换为IOrderedQueryable var orderedQuery = query.OrderBy(b => b.BookId); ViewBag.RootPath = "/upload/thumbnailimage/"; int pageSize = 3; int pageNumber = (page ?? 1); // 直接传入有序查询到分页方法 var pagedModel = await PagingList<BookListViewModel>.CreateAsync(orderedQuery, pageNumber, pageSize); return View(pagedModel); }
视图中的分页实现示例
你可以在Index视图里利用PagingList提供的属性来生成分页链接,比如:
@model PagingList<BookListViewModel> <!-- 这里渲染你的书籍列表 --> @foreach (var book in Model) { <div>@book.BookName - @book.AuthorName</div> } <!-- 分页导航 --> <div class="pagination"> @if (Model.HasPreviousPage) { <a asp-action="Index" asp-route-page="@(Model.PageNumber - 1)">上一页</a> } @for (int i = 1; i <= Model.TotalPages; i++) { <a asp-action="Index" asp-route-page="@i" class="@(i == Model.PageNumber ? "active" : "")">@i</a> } @if (Model.HasNextPage) { <a asp-action="Index" asp-route-page="@(Model.PageNumber + 1)">下一页</a> } </div>
这样既解决了你的转换错误,又优化了查询性能,还能正常实现分页功能。
内容的提问来源于stack exchange,提问作者topcool
相关产品推荐
相关产品推荐

