将PagedList与ViewModel ASP.Net MVC一起使用

我正在尝试在我的ASP.Net应用程序中使用PagedList,我在微软网站上找到了这个例子http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/sorting -filtering-和寻呼与-的entity frameworkfunction于一个-ASP净MVC-应用

在使用ViewModel的复杂情况下如何使用PagedList? 我试图在没有成功的情况下将PagedList添加到此处发布的教师示例中: http : //www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/reading-related-data-with -the-entity frameworkfunction于一个-ASP净MVC-应用

问题是ViewModel由类而不是简单字段组成,因此我无法使用ToPageList()方法转换结果。

这是ViewModel结构:

using System.Collections.Generic; using ContosoUniversity.Models; namespace ContosoUniversity.ViewModels { public class InstructorIndexData { public IEnumerable Instructors { get; set; } public IEnumerable Courses { get; set; } public IEnumerable Enrollments { get; set; } } } 

我需要将三个表连接到ViewModel并在View中显示结果。

对于试图在不修改ViewModel并且不从数据库中加载所有记录的任何人。

知识库

  public List GetOrderPage(int page, int itemsPerPage, out int totalCount) { List orders = new List(); using (DatabaseContext db = new DatabaseContext()) { orders = (from o in db.Orders orderby o.Date descending //use orderby, otherwise Skip will throw an error select o) .Skip(itemsPerPage * page).Take(itemsPerPage) .ToList(); totalCount = db.Orders.Count();//return the number of pages } return orders;//the query is now already executed, it is a subset of all the orders. } 

调节器

  public ActionResult Index(int? page) { int pagenumber = (page ?? 1) -1; //I know what you're thinking, don't put it on 0 :) OrderManagement orderMan = new OrderManagement(HttpContext.ApplicationInstance.Context); int totalCount = 0; List orders = orderMan.GetOrderPage(pagenumber, 5, out totalCount); List orderViews = new List(); foreach(Order order in orders)//convert your models to some view models. { orderViews.Add(orderMan.GenerateOrderViewModel(order)); } //create staticPageList, defining your viewModel, current page, page size and total number of pages. IPagedList pageOrders = new StaticPagedList(orderViews, pagenumber + 1, 5, totalCount); return View(pageOrders); } 

视图

 @using PagedList.Mvc; @using PagedList; @model IPagedList @{ ViewBag.Title = "Index"; } 

Index

@Html.ActionLink("Create New", "Create")

@if (Model.Count > 0) {
@Html.DisplayNameFor(model => model.First().orderId)
} else {

No Orders yet.

} @Html.PagedListPager(Model, page => Url.Action("Index", new { page }))

奖金

首先做,然后或许使用这个!

由于这个问题是关于(视图)模型的,我将为您提供一个小解决方案,它不仅对分页有用,而且对于您的应用程序的其余部分,如果您想要将实体分开,仅用于存储库,让应用程序的其余部分处理模型(可以用作视图模型)。

知识库

在您的订单存储库(在我的例子中)中,添加一个静态方法来转换模型:

 public static OrderModel ConvertToModel(Order entity) { if (entity == null) return null; OrderModel model = new OrderModel { ContactId = entity.contactId, OrderId = entity.orderId, } return model; } 

在您的存储库类下面,添加:

 public static partial class Ex { public static IEnumerable SelectOrderModel(this IEnumerable source) { bool includeRelations = source.GetType() != typeof(DbQuery); return source.Select(x => new OrderModel { OrderId = x.orderId, //example use ConvertToModel of some other repository BillingAddress = includeRelations ? AddressRepository.ConvertToModel(x.BillingAddress) : null, //example use another extension of some other repository Shipments = includeRelations && x.Shipments != null ? x.Shipments.SelectShipmentModel() : null }); } } 

然后在你的GetOrderPage方法中:

  public IEnumerable GetOrderPage(int page, int itemsPerPage, string searchString, string sortOrder, int? partnerId, out int totalCount) { IQueryable query = DbContext.Orders; //get queryable from db .....//do your filtering, sorting, paging (do not use .ToList() yet) return queryOrders.SelectOrderModel().AsEnumerable(); //or, if you want to include relations return queryOrders.Include(x => x.BillingAddress).ToList().SelectOrderModel(); //notice difference, first ToList(), then SelectOrderModel(). } 

让我解释:

静态ConvertToModel方法可以被任何其他存储库访问,如上所述,我使用来自某些AddressRepository ConvertToModel

扩展类/方法允许您将实体转换为模型。 这可以是IQueryable或任何其他列表,集合

现在有了神奇之处:如果您在调用SelectOrderModel()扩展名之前执行了查询,则扩展内的includeRelations将为true,因为source不是数据库查询类型(不是linq-to-sql IQueryable )。 如果是这样,扩展可以调用整个应用程序中的其他方法/扩展来转换模型。

现在另一方面:您可以先执行扩展,然后继续进行LINQ过滤。 过滤最终会在数据库中发生 ,因为你还没有.ToList() ,扩展只是处理你的查询的一层。 Linq-to-sql最终将知道在数据库中应用哪些过滤。 inlcudeRelations将为false,因此它不会调用SQL无法理解的其他c#方法。

它起初看起来很复杂,扩展可能是新的,但它确实很有用。 最后,当你为所有存储库设置了它时,只需一个.Include() extra来加载关系。

正如克里斯所说,你使用ViewModel的原因并不能阻止你使用PagedList 。 您需要形成一组ViewModel对象,这些对象需要发送到视图以进行分页。

以下是有关如何将PagedList用于viewmodel数据的分步指南。

您的viewmodel( 为简洁起见,我举了一个简单的示例,您可以轻松修改它以满足您的需求。

 public class QuestionViewModel { public int QuestionId { get; set; } public string QuestionName { get; set; } } 

你的控制器的Index方法就像

 public ActionResult Index(int? page) { var questions = new[] { new QuestionViewModel { QuestionId = 1, QuestionName = "Question 1" }, new QuestionViewModel { QuestionId = 1, QuestionName = "Question 2" }, new QuestionViewModel { QuestionId = 1, QuestionName = "Question 3" }, new QuestionViewModel { QuestionId = 1, QuestionName = "Question 4" } }; int pageSize = 3; int pageNumber = (page ?? 1); return View(questions.ToPagedList(pageNumber, pageSize)); } 

和您的索引视图

 @model PagedList.IPagedList @using PagedList.Mvc;   @foreach (var item in Model) {  } 
@Html.DisplayFor(modelItem => item.QuestionId) @Html.DisplayFor(modelItem => item.QuestionName)

Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount @Html.PagedListPager( Model, page => Url.Action("Index", new { page }) )

这是我的答案的SO链接 ,它有关于如何使用PageList的分步指南

我修改了代码如下:

视图模型

 using System.Collections.Generic; using ContosoUniversity.Models; namespace ContosoUniversity.ViewModels { public class InstructorIndexData { public PagedList.IPagedList Instructors { get; set; } public PagedList.IPagedList Courses { get; set; } public PagedList.IPagedList Enrollments { get; set; } } } 

调节器

 public ActionResult Index(int? id, int? courseID,int? InstructorPage,int? CoursePage,int? EnrollmentPage) { int instructPageNumber = (InstructorPage?? 1); int CoursePageNumber = (CoursePage?? 1); int EnrollmentPageNumber = (EnrollmentPage?? 1); var viewModel = new InstructorIndexData(); viewModel.Instructors = db.Instructors .Include(i => i.OfficeAssignment) .Include(i => i.Courses.Select(c => c.Department)) .OrderBy(i => i.LastName).ToPagedList(instructPageNumber,5); if (id != null) { ViewBag.InstructorID = id.Value; viewModel.Courses = viewModel.Instructors.Where( i => i.ID == id.Value).Single().Courses.ToPagedList(CoursePageNumber,5); } if (courseID != null) { ViewBag.CourseID = courseID.Value; viewModel.Enrollments = viewModel.Courses.Where( x => x.CourseID == courseID).Single().Enrollments.ToPagedList(EnrollmentPageNumber,5); } return View(viewModel); } 

视图

 
Page @(Model.Instructors.PageCount < Model.Instructors.PageNumber ? 0 : Model.Instructors.PageNumber) of @Model.Instructors.PageCount @Html.PagedListPager(Model.Instructors, page => Url.Action("Index", new {InstructorPage=page}))

我希望这会对你有所帮助!!

我想出了如何做到这一点。 我正在构建一个非常类似于您在原始问题中讨论的示例/教程的应用程序。

这是代码片段,对我有用:

  int pageSize = 4; int pageNumber = (page ?? 1); //Used the following two formulas so that it doesn't round down on the returned integer decimal totalPages = ((decimal)(viewModel.Teachers.Count() /(decimal) pageSize)); ViewBag.TotalPages = Math.Ceiling(totalPages); //These next two functions could maybe be reduced to one function....would require some testing and building viewModel.Teachers = viewModel.Teachers.ToPagedList(pageNumber, pageSize); ViewBag.OnePageofTeachers = viewModel.Teachers; ViewBag.PageNumber = pageNumber; return View(viewModel); 

我补充道

 using.PagedList; 

按照教程说明我的控制器。

现在在我看来我在顶部使用语句等,注意我没有改变我的使用模型语句。

 @model CSHM.ViewModels.TeacherIndexData @using PagedList; @using PagedList.Mvc;  

然后在底部建立我的分页列表我使用以下,它似乎工作。 我还没有内置当前排序function,显示相关数据,filter等,但我不认为这将是那么困难。

 Page @ViewBag.PageNumber of @ViewBag.TotalPages @Html.PagedListPager((IPagedList)ViewBag.OnePageofTeachers, page => Url.Action("Index", new { page })) 

希望对你有用。 让我知道它是否有效!!

您使用视图模型的事实没有影响。 使用PagedList的标准方法是将“一页项目”存储为ViewBag变量。 您需要确定的是您将要分页的内容。 您不能同时逻辑地分页多个集合,因此假设您选择了Instructors

 ViewBag.OnePageOfItems = myViewModelInstance.Instructors.ToPagedList(pageNumber, 10); 

然后,标准代码的其余部分一如既往地工作。