【问题标题】:Implement Paged List with IList IEnumerable Repository使用 IList IEnumerable 存储库实现分页列表
【发布时间】:2020-10-13 19:15:41
【问题描述】:

我继承了一个项目,并要求在我们所有的存储库中实现分页(500 多种方法),以便在 Web 前端仅显示数据片段。

当前存储库如下。它们返回任务列表、IEnumerables 等。

我们将如何完成并为以下存储库示例实现分页?

如果我实现以下分页列表答案,则存储库返回 IList,而不是 IQueryable。所以答案仍然是先检索所有数据(导致性能问题),然后过滤它。

https://stackoverflow.com/a/5036023/12425844

存储库:

public Task<List<Product>> GetProductListByProductNumber(int bkProductNumber)
{
    var productData = _context.Product
        .Include(c => c.LkProducttype)
        .Where(c => c.BkProductnumber == bkProductNumber).ToListAsync();
    return productData ;
}


public Task<List<Product>> GetProductListByProductDescription(string productDescription)
{
    var productData = _context.Product
        .Include(c => c.LkProducttype)
        .Where(c => c.ProductDescription == productDescription).ToListAsync();
    return productData;
}

页面列表答案

public PagedList<T> Find(Expression<Func<T,bool>> predicate, int pageNumber, pageSize)
{
   return repository
             .Find()
             .Where(predicate)
             .ToPagedList(pageNumber, pageSize);
}

*寻找一种有效的方法,所以如果可能的话,不必重新复制和粘贴所有 500 多种分页方法

如果将所有 Repos 方法更改为 IQueryable,这可能会解决问题。但是,阅读 Repos should Not return IQueryable per article here Entity Framework Repository Pattern why not return Iqueryable?

【问题讨论】:

  • 你可以用 ToPagedList() 代替对 ToListAsync() 的调用
  • 嗨@EnasOsama 那么我该如何处理不需要分页的原始存储库?我也需要它们,谢谢
  • 要处理分页,返回的对象必须不同以保存有关总计数和当前页面的信息。你打算如何处理这个问题,以便我可以尝试提供帮助:)
  • 也许放置一个参数作为存储库名称,寻找任何解决方案,试图了解自己? @EnasOsama
  • 好吧,我现在唯一能想到的就是也许你可以编辑 .ToPagedList() 扩展方法来处理这个问题。它可以采用可选的分页参数。如果存在,则使用分页版本,否则使用常规 ToListAsync()。唯一的问题是你必须有一个包装对象来处理这两种情况或使用动态作为返回对象

标签: c# .net linq .net-core repository


【解决方案1】:

如果您想准确返回页面的数据,您可以使用 LINQ .Skip 和 .Take,它仍然会返回 IQueryable

public Task<List<Product>> GetProductListByProductNumberAsync(int bkProductNumber, int pageNumber, int pageSize)
{
    var productData = _context.Product
        .Include(c => c.LkProducttype)
        .Where(c => c.BkProductnumber == bkProductNumber)
        .Skip(pageSize * (pageNumber - 1))
        .Take(pageSize)
        .ToListAsync();
    return productData;
}

这种方法的默认设置是,如果定期出现新数据,您的页面可能会失去同步。例如,您查询第 2 页,25 个项目,得到 25-49。然后插入 2 个新项目并查询第 3 页,您将得到以前的 48-72 但这是大多数网站的标准行为。

现在要解决 DRY 问题,如果您想保留现有查询,我将首先将查询本身与转换为异步列表分开:

  private IQueryable<Product> GetProductListByProductNumberQuery(int bkProductNumber)
        {
            var productData = _context.Product
                .Include(c => c.LkProducttype)
                .Where(c => c.BkProductnumber == bkProductNumber);
            return productData;
        }

然后根据需要添加使用可查询的方式(使用扩展方法的示例,但可以使用要包装的类来完成,或者在您的存储库中使用 2 种调用可查询的方式):

  public static class QueryableExtensions
    {
        public static Task<List<T>> ToTask<T>(this IQueryable<T> query) 
        {
            return query.ToListAsync(); // might as well call directly .ToListAsync
        }

        public static Task<List<T>> ToTaskPaged<T>(this IQueryable<T> query, int pageNumber, int pageSize)
        {
            return query
                .Skip(pageSize * (pageNumber-1))
                .Take(pageSize)
                .ToListAsync();
        }
    }

ToListAsync 的不同使用允许返回查询以通过分页对其进行细化

查询是公开的还是私有的,取决于您希望如何使用它们。如果您认为存储库负责提供查询而不是如何运行它们,那么查询将是公开的。如果您希望您的存储库仅公开包装的已执行查询,则查询将是私有的。 好的做法是不返回 IQueryable,但这会违反您设置的约束,即您不想为每个查询创建 2 个版本(分页,而不是分页),因此使用该约束,我将公开 IQueryable。但是您链接的文章是正确的,警告用户可以开始用它做疯狂的事情。如果它只暴露给你的团队,我认为只要每个人都知道这是技术债务就可以了。 如果它在公共 API 中,那么您以后无法修复它。

【讨论】:

  • 如果针对 DRY 问题进行了改进(完全合法,我没有让您也想保留以前的方法),但是对于如何避免像您之前的人一样编辑 500 个方法,我没有想到将查询本身及其用途包装在一起,因此您无法再访问 IQueryable
  • 根据您对公共 IQueryable 的关注进行了一些改进,但要明确一点:我不建议正常公开 IQueryable。它与您的约束一起工作,我认为这与您完成任务的时间有关。否则我会硬着头皮做 2 个公共方法,一个有分页,一个没有分页,都使用相同的私有可查询生成器。但这是要添加的 500 种方法。
  • 是的,这就是为什么我将 IQueryable 设为 Private,然后将 List Enumerable Queries 设为 Public,你的策略很有意义!
  • 还有一个使用默认参数作为 pagingOptions 参数的解决方案,但这也不是一个好的设计。但是如果你真的想避免 500 个额外的方法并且仍然不返回 IQueryable,我们可以研究一下。
  • 是的,很乐意看看替代品
猜你喜欢
  • 1970-01-01
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
  • 2014-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多