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