对于任何试图在不修改 ViewModel 且不从数据库加载所有记录的情况下执行此操作的人。
存储库
public List<Order> GetOrderPage(int page, int itemsPerPage, out int totalCount)
{
List<Order> orders = new List<Order>();
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<Order> orders = orderMan.GetOrderPage(pagenumber, 5, out totalCount);
List<OrderViewModel> orderViews = new List<OrderViewModel>();
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<OrderViewModel> pageOrders = new StaticPagedList<OrderViewModel>(orderViews, pagenumber + 1, 5, totalCount);
return View(pageOrders);
}
View
@using PagedList.Mvc;
@using PagedList;
@model IPagedList<Babywatcher.Core.Models.OrderViewModel>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div class="container-fluid">
<p>
@Html.ActionLink("Create New", "Create")
</p>
@if (Model.Count > 0)
{
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.First().orderId)
</th>
<!--rest of your stuff-->
</table>
}
else
{
<p>No Orders yet.</p>
}
@Html.PagedListPager(Model, page => Url.Action("Index", new { page }))
</div>
Bonus
先做上面的,然后也许用这个!
由于这个问题是关于(视图)模型的,我将为您提供一个小解决方案,它不仅对分页有用,而且对于您的应用程序的其余部分(如果您想保持实体独立),仅用于存储库,并让应用程序的其余部分处理模型(可以用作视图模型)。
存储库
在您的订单存储库中(在我的例子中),添加一个静态方法来转换模型:
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<OrderModel> SelectOrderModel(this IEnumerable<Order> source)
{
bool includeRelations = source.GetType() != typeof(DbQuery<Order>);
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
method:
public IEnumerable<OrderModel> GetOrderPage(int page, int itemsPerPage, string searchString, string sortOrder, int? partnerId,
out int totalCount)
{
IQueryable<Order> 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
方法可以通过任何其他存储库访问,如上所述,我使用ConvertToModel
来自一些AddressRepository
.
扩展类/方法允许您将实体转换为模型。这可以是 IQueryable 或任何其他列表、集合.
现在神奇之处来了:如果您在调用之前执行了查询SelectOrderModel()
扩大,includeRelations
扩展内将为 true,因为source
不是数据库查询类型(不是 linq-to-sqlIQueryable
)。如果这是真的,扩展可以在整个应用程序中调用其他方法/扩展来转换模型。
现在在另一边:您可以先执行扩展,然后继续进行 LINQ 过滤。过滤最终将在数据库中进行,因为你没有做.ToList()
然而,扩展只是处理您的查询的一层。 Linq-to-sql 最终将知道在数据库中应用什么过滤。这inlcudeRelations
将为 false,以便它不会调用 SQL 无法理解的其他 C# 方法。
乍一看似乎很复杂,扩展可能是新的东西,但它确实很有用。最终,当您为所有存储库设置完毕后,只需.Include()
extra 将加载关系。