不,分页列表之前不需要 10 条记录。您的代码的显示方式,AutoMapper 将导致查询在到达分页列表之前延迟执行,这意味着它将返回所有数据(假设 1000 条记录)。然后PagedList会正确检索到已经物化的List中的10条,并识别出总记录量为1000条。
我认为您想在数据库中过滤 10,这具有更好的性能,因此您应该在您的数据库实体的 IQueryable 中使用 PagedList,如下所示:
List<Product> filteredProducts = dbContext.Products.OrderBy(p => p.ProductId).ToPagedList(pageNumber, 10);
return Mapper.Map<List<Product>, List<ProductViewModel>>(filteredProducts);
OrderBy 是 PagedList 的必填项。
小心使用自动映射器
考虑以下场景。如果您的Product 实体与ProductReview(ICollection<ProductReview>)有这样的子关系怎么办:
public class ProductReview
{
public int ProductId { get; set; }
public string Description { get; set; }
public int ReviewerId { get; set; }
public double Score { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<ProductReview> Reviews { get; set; }
}
...您的ProductViewModel 有一个int 属性ReviewsCount 显示在您的视图中?
当Automapper 将映射和转换您的实体到视图模型时,它将访问列表中每个产品的Reviews 属性(假设您的情况为10),一个一,让Reviews.Count() 填写ReviewsCount 到你的ProductViewModel。
考虑到我的示例,在该示例中,我从不急切加载 Reviews 的产品,如果打开 延迟加载,AutoMapper 将执行十个查询(每个产品一个)以计算 Reviews。计数是一项快速操作,十个产品只是其中的几个。但是,如果您实际上将ProductReview 映射到ProductReviewViewModel 而不是计数,这将有点重。如果关闭延迟加载,我们会得到一个异常,因为Reviews 将是null。
一种可能的解决方案是在映射期间预先加载您可能需要的所有子项,如下所示:
List<Product> filteredProducts = dbContext.Products.Include("Reviews").OrderBy(p => p.ProductId).ToPagedList(pageNumber, 10);
return Mapper.Map<List<Product>, List<ProductViewModel>>(filteredProducts);
...所以 10 个产品及其评论将在一个查询中检索,AutoMapper 不会执行其他查询。
但是.......我只需要一个计数,我真的需要检索 ALL Reviews 以避免多次查询吗?
加载所有评论和所有昂贵的字段(如 Description 可能有数千个字符)不是也很繁重吗???
是的,当然。避免在这些情况下将PagedList 与AutoMapper 混合使用。
只要做一个这样的投影:
List<Product> filteredProducts = dbContext.Products
.Select(p => new ProductViewModel
{
ProductId = p.ProductId,
ProductName = p.Name,
ProductDescription = p.Description,
ReviewsCount = p.Reviews.Count(),
ScoreAverage = p.Reviews.Select(r => r.Score).DefaultIfEmpty().Average()
})
.OrderBy(p => p.ProductId).ToPagedList(pageNumber, 10);
现在您正在加载 10 个产品,将它们投影到 ProductViewModel,计算 Reviews 计数和平均得分,而不从数据库中检索所有 Reviews。
当然,在某些情况下,您可能确实需要加载/实现所有子实体,但除此之外,还需要投影 ftw。
您还可以将Select() 部分放在扩展类中,并将所有投影封装在扩展方法中,这样您就可以像使用AutoMapper 一样重用它们。
我并不是说AutoMapper 是邪恶的,你不应该使用它,我自己在某些情况下使用它,你只需要在适当的时候使用它。
编辑:AUTOMAPPER 支持投影
我找到了this question @GertArnold 解释了以下关于AutoMapper 的内容:
...增加了对被翻译的投影的支持的代码库
进入表达式,最后进入 SQL
所以开心就好,听从他的建议。