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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:51:55