IPagedList.MVC,设置总大小
本文关键字:设置 MVC IPagedList | 更新日期: 2023-09-27 17:59:32
我正在使用asp.net MVC 5构建一个应用程序,并有一个使用IPagedList.MVC 4.5.0.0版本、AutoMapper和实体框架的网格。
在这个项目中,我有一个BusinessLayer,这就是我的Action所要说的,因为我不希望Action方法直接与Entity Framework对话。所以我的BLL有以下方法:
public IPagedList<ActiveContractViewModel> GetAllContracts(string regNumFilter, int page)
{
var lstcontractViewModel = new List<ActiveContractViewModel>();
using (ActiveContractRepository activeContractRepos = new ActiveContractRepository(new UnitOfWork()))
{
var activeContractList = activeContractRepos.All.OrderByDescending(x => x.Id).Include(c => c.Contractor);
if (regNumFilter.Trim().Length > 0)
{
activeContractList = activeContractRepos.All.Where(x => x.RegistrationNumber.Contains(regNumFilter)).OrderByDescending(x => x.Id).Include(c => c.Contractor);
}
foreach (var activeContract in activeContractList)
{
Mapper.CreateMap<DomainClasses.ActiveContract, ActiveContractViewModel>().ForMember(dest => dest.ContractorModel, opts => opts.MapFrom(src => new ContractorViewModel
{
Id = src.Contractor.Id,
Name = src.Contractor.Name,
ContactPerson = src.Contractor.ContactPerson,
Phone = src.Contractor.Phone,
Fax = src.Contractor.Fax,
Address = src.Contractor.Address,
VendorNumber = src.Contractor.VendorNumber,
FederalTaxId = src.Contractor.FederalTaxId
}
));
Mapper.AssertConfigurationIsValid();
lstcontractViewModel.Add(Mapper.Map<ActiveContractViewModel>(activeContract));
}
}
return lstcontractViewModel.ToPagedList(page, 20);
}
我正在将我的ActiveContract类(从Entity Framework)映射到一个模型(ActiveContractVieWModel),它运行良好,可以返回数据并进行分页。但我在调试时注意到,foreach循环也会遍历所有记录,如果我有2500条记录,它会遍历所有的记录,构建一个大列表,然后在ToPageList方法中使用。
有没有更好的方法来绕过这一点,这样我就可以建立我的模型,只填写我需要的20条记录,并让IPagedList知道总大小?
我最终查看了IPageList.MVC的更多内容,并看到作者发布了关于这一点的帖子:https://github.com/troygoode/pagedlist#example-2手动分页
"在某些情况下,您无法访问能够创建IQueryable的东西,例如使用.Net的内置MembershipProvider的GetAllUsers方法。此方法提供分页,但不能通过IQueryaable。幸运的是,PagedList仍然支持您(请注意StaticPagedList的使用):"
我改为使用StaticPagedList,它现在工作得更好了,只需要获取我想要的记录数量,分页也能工作。
这是因为您正在检索所有项目。在您的LINQ查询中,您仅通过regNumFilter
进行筛选
var activeContractList = activeContractRepos
.All
.OrderByDescending(x => x.Id)
.Include(c => c.Contractor);
activeContractList = activeContractRepos
.All
.Where(x => x.RegistrationNumber.Contains(regNumFilter))
.OrderByDescending(x => x.Id)
.Include(c => c.Contractor);
要检索特定数量的行(在每页20个项目的情况下),请在迭代结果之前使用Skip()
和Take()
。
示例代码:
var activeContractList = activeContractList
.Skip(20 * page)
.Take(20);
foreach (var activeContract in activeContractList)
{
....
}
我使用的不是automapper,而是valueinjecter
。
我所做的是将IList<TModel>
"映射"到IList<TViewModel>
,这样你就不会有代码了。它会更干净。
PagedList
不知道TEntity
,它只是进行寻呼。别忘了分页是懒惰的。
使用Valueinjecter
,我有以下代码:
https://github.com/fatagun/NetCollab/blob/master/NetCollab.Web/Mappers/Mapper.cs
我认为您需要的是AutoMapper可查询扩展。
当您使用IEnumerable<T>
接口时,下划线实体查询会具体化。因此,在ToPagedList"占用"answers"跳过"某些页面之前,查询将针对整个表运行。相反,您将不得不使用IQueryable<T>
变体。
当使用带有AutoMapper标准Mapper.Map函数的ORM(如NHibernate或Entity Framework)时,您可能会注意到,当AutoMapper试图将结果映射到目标类型时,ORM将查询图中所有对象的所有字段