PagedList 使用 LINQ Skip and Take,但使用 Count of results 显示分页

Posted

技术标签:

【中文标题】PagedList 使用 LINQ Skip and Take,但使用 Count of results 显示分页【英文标题】:PagedList using LINQ Skip and Take, but show paging using Count of results 【发布时间】:2013-11-25 09:10:22 【问题描述】:

我正在尝试根据类别过滤器和 ItemsPerPage 显示经过过滤的产品列表,但在尝试将其与 PagedList 一起使用时遇到了一些问题。

如果我需要编写自己的分页代码,或者有没有办法使用 PagedList 获得所需的结果,具有 PagedList 专业知识的人可以建议我。

我正在使用 LINQ 的 Skip & Take 函数来仅获取需要在当前页面上显示的行数,但我仍然希望分页链接根据过滤器的总数显示页面。

例如: 我的搜索过滤器找到 50 个结果,但由于我每页的行数是 10 个项目,所以我使用 LINQ 的 Skip() 和 Take() 只返回 10 行。我仍然需要在我的 View.cshtml 中显示页面链接 > 现在使用默认的 PagedList,我只得到 >,我知道为什么我只看到一个页面,但只是想知道如何让它显示正确数量的页面链接,而只得到结果的一个子集。

**我的目标是将优化的查询写入数据库,以便网页响应性能更快。

这是我的 Action Method 代码的样子。代码得到了正确的结果,但分页无法正常工作:

public ViewResult List(int page =1, string category =null)

    if (category != null) this.CurrentCategory = category;

    var products = repository.Products
                    .Where(p => this.CurrentCategory == null || p.Category == this.CurrentCategory)
                    .OrderBy(p => p.ProductID)
                    .Skip((page -1) * PageSize)
                    .Take(PageSize);

    return View(products.ToList().ToPagedList(page, PageSize));

这是视图中处理分页的代码 sn-p。我查看了项目的 Github 站点,但找不到提供自定义页面的扩展方法。我认为它只会根据“每页项目”和@Model 中产品的 Count() 呈现页面数:

@model IPagedList<Product>

//foreach loop that renders the @Model

//Code that displays the pagination using PagedList
<div style="text-align:center">
    @Html.PagedListPager(Model, page => Url.Action("List", new  page = page, category =  ViewBag.CurrentCategory ), PagedListRenderOptions.OnlyShowFivePagesAtATime
    )
</div>

【问题讨论】:

你有没有得到这个答案?我有同样的问题,我没有看到自己检索所有记录,以便我们可以显示正确的寻呼号码。请告诉我 您好 Johnny,答案是自定义过滤,您需要编写自己的代码来处理分页。 PagedList 是一个很棒的分页库,但它不提供过滤和仅返回子集以优化大量数据。 那么实现这一目标的最终答案是什么???? 【参考方案1】:

我遇到了完全相同的问题,最终我使用了 StaticPagedList。你可以这样做

public ViewResult List(int page =1, string category =null)

    if (category != null) this.CurrentCategory = category;

    var products = repository.Products
                   .Where(p => this.CurrentCategory == null || p.Category == this.CurrentCategory)
                   .OrderBy(p => p.ProductID)
                   .Skip((page -1) * PageSize)
                   .Take(PageSize);

var count = repository.Products
                   .Where(p => this.CurrentCategory == null || p.Category == this.CurrentCategory).Count();

var resultAsPagedList = new StaticPagedList<Product>(products, page, PageSize, count);

    return View(resultAsPagedList);

至于视图,只需要替换模型类型即可

@model StaticPagedList<Product>

【讨论】:

我对从服务调用返回的行列表做同样的事情。唯一的区别是我将视图模型保留为 IPagedList。例如。 @model IPagedList 在你的情况下。 你是生命的救星 很想知道PagedList和StaticPagedList有什么区别?【参考方案2】:

ToPagedList 在内部使用TakeSkip,当您使用IQueryable&lt;T&gt; 类的扩展时,这将导致您需要的数据库查询。它还将TotalItemCount 检索到其元数据中。

有时您可能需要将查询结果带入内存,因为您使用的方法无法翻译成 sql。这意味着您必须将PagedList 转换回Enumerable。你可以通过使用StaticPagedList 方法来解决这个问题,如下所示:

   var superset= repository.Products
      .Where(p => this.CurrentCategory == null 
             || p.Category == this.CurrentCategory)
      .OrderBy(p => p.ProductID)
      .ToPagedList(page, PageSize);

   var subset = superset
      .AsEnumerable()
      .Select(p => new ProductViewModel
      
          OtherData = p.UntranslateableMethod()  
      )

    var model = new StaticPagedList<ProductViewModel>(subset,
       superset.GetMetaData());

来自cmets中方法的总结:

初始化 PagedList.StaticPagedList 类的新实例 包含已经划分的子集和关于 超集的大小和子集在其中的位置。

【讨论】:

这是正确答案。您可以通过调用“OnePageOfItems.TotalItemCount”来获取项目的总列表,我使用 miniprofiler 运行 SQL 和计时。您可以进行两次调用(一次用于计算对象总数,然后一次用于获取对象本身的列表),并将它们传递到静态分页列表中。但是,使用 IOrderedQueryable 调用 IPagedList 将在内部产生完全相同的 SQL 调用。所以这样做更有意义,然后调用 .TotalItemCount。【参考方案3】:

您仍然可能需要单独要求计数。

var products = repository.Products
                         .Where(p => this.CurrentCategory == null || p.Category == this.CurrentCategory);
var numProds = products.Count();
var mypage = products.OrderBy(p => p.ProductID)
                     .Skip((page -1) * PageSize)
                     .Take(PageSize);

【讨论】:

感谢您的回复。我的问题是如何自定义 PagedList 框架以显示自定义分页方案。我知道如何过滤我的搜索并获得 results.Count()。但到目前为止,我将 Count() 插入 PagedList 的所有尝试都失败了。在开始编写自己的自定义分页之前,我想看看是否可以使用 PagedList 实现自定义,因为它是一个不错的分页框架。 啊。您还必须分享您的视图代码,看看那里是否有问题。 嗨 DigitalD,我更新了我的第一个帖子以显示视图的 Razor/C# 代码以显示分页代码。 @MonojitSarkar 是的,它会两次访问数据库。一次用于总计数,一次用于加载过滤后的结果页面。【参考方案4】:

如果使用 PagedList 的方法,则不需要同时使用 LINQ .skip().take()。如果这样做,那么您将预先限制列表,使用该库将毫无意义,因为您首先通过.skip().take() 过滤列表以获取pagesize 结果,然后传递那些pagesize结果要再次过滤到pagesize,当然是一样的,但是PagedList不知道总数是多少。

如果您想确保不会加载所有结果,只需将 IQueryable 发送到 PagedList 而不是 EnumerableList。 PagedList 将为您添加.Skip().Take(),您的数据库将只返回这些结果。

【讨论】:

感谢 Juventus18 的反馈,但请在尝试回答之前仔细阅读并理解问题。 @badboy11 and understand it 似乎有点苛刻。如果某人还没有理解某事......有多大可能......他们会奇迹般地意识到他们误解了这个问题。 please read the question carefully 在我看来......这就是所有需要说的。不要气馁,或者至少对你的批评更有建设性。 @badbou11 - 我完全理解你写的内容。也许你没有写好你的问题。 “我怎样才能让它显示正确数量的页面链接,同时只获得结果的一个子集。”正如我所说,这是因为您在将列表传递给PagedList 之前对其进行了预先限制。不要在查询中使用.Skip().Take(),因为PagedList 会为您执行此操作。如果您像您所做的那样只传递分页列表 10 个项目(或者,一个只返回 10 个项目的查询)并告诉它每页 10 个项目,那只有一页,所以它只会呈现一页。 如果您想确保您的数据库只返回分页结果而不是整个集合,请从您的 repo 发送 PagedListIQueryable 而不是 IEnumerableIList(不是从您的示例中清楚您的回购返回的内容)。无论哪种情况,您都不需要在将结果传递给PagedList之前使用Skip()Take()【参考方案5】:

上面的解释是正确的。 但是当你分配静态选择列表时..

new StaticPagedList<Product>(products, page, PageSize, count);.

它显示的页面链接数比实际计数少。 如果 Count 为 10,如果您的页面大小为 5,则它仅显示 2 页..

如果您想在计数中显示所有可用的页面链接, 那么

pass count*5 ie count*pagesize

new StaticPagedList<Product>(products, page, PageSize, count*5);//in my case page size is 5

或new StaticPagedList(products, page, PageSize, count*pagesize);

因此它提供了页面中所有可用的计数。

【讨论】:

你引用的是this的答案,对吧?

以上是关于PagedList 使用 LINQ Skip and Take,但使用 Count of results 显示分页的主要内容,如果未能解决你的问题,请参考以下文章

是否可以使用 LINQ 的 Skip 方法忽略列表项,然后在列表上应用 skip 而不会丢失该项目?

LinQ中Skip()方法和Take()方法的使用

Linq 使用skip和take分页

Linq 使用skip和take分页

Linq 使用skip和take分页

使用 Linq Skip Take 进行传统 SQL 查询,而不是使用 RowNum