【问题标题】:C# Entity Framework PaginationC# 实体框架分页
【发布时间】:2012-04-26 02:41:04
【问题描述】:

有没有一种方法可以获取复杂 Linq 查询的行数和数百万条记录 无需两次访问数据库或编写 2 个单独的查询??

我可能有自己的建议。写一个存储过程,但我擅长 MySQL 而不是 MSSQL。

任何更好的建议都会很棒。另外,如果有人知道微软是否正在努力将此功能添加到实体框架中。

【问题讨论】:

  • 我非常有信心,如果不访问数据库或编写与实际返回这些行的查询分开的查询,您就无法获得查询中的行数。
  • 感谢@JonathanWood 的想法!
  • 当您在 EF 中使用 .Count() 时,它不会选择所有行,它只会执行 select count() from table sql 语句 - 所以虽然您确实需要 2 个查询,但其中一个非常便宜。
  • @JK select count() 一点都不便宜!实际上它与实际获取数据的复杂性几乎相同,唯一的区别是它只计算行而不是获取行。但它仍然必须执行所有扫描等。
  • 如果我有一个复杂的查询,它只计算结果,可能是 10,000+,另一个只会抓取其中 20 个结果。 Count() 会对整个过程征税吗?

标签: c# entity-framework pagination


【解决方案1】:

我创建了一个为您进行分页的 nuget 库。 https://github.com/wdunn001/EntityFrameworkPaginateCore

将 nuget 添加到项目中

安装包EntityFrameworkPaginateCore 添加

使用 EntityFrameworkPaginateCore; 给你的供应商

有 1 个方法和 2 个重载,该方法重载允许排序和过滤。使用排序对象和过滤器对象

public async Task<Page<Example>> GetPaginatedExample(
            int pageSize = 10, 
            int currentPage = 1, 
            string searchText = "", 
            int sortBy = 2
            )
        {
            var filters = new Filters<Example>();
                filters.Add(!string.IsNullOrEmpty(searchText), x => x.Title.Contains(searchText));

            var sorts = new Sorts<Example>();
            sorts.Add(sortBy == 1, x => x.ExampleId);
            sorts.Add(sortBy == 2, x => x.Edited);
            sorts.Add(sortBy == 3, x => x.Title);

            try
            {
                return await _Context.EfExample.Select(e => _mapper.Map<Example>(e)).PaginateAsync(currentPage, pageSize, sorts, filters);
            }
            catch (Exception ex)
            {
                throw new KeyNotFoundException(ex.Message);
            }
        }

【讨论】:

    【解决方案2】:

    如果您需要快速解决方案,您可以使用 XPagedList https://github.com/dncuug/X.PagedList。 XPagedList 是一个库,可让您轻松获取 IEnumerable/IQueryable,将其分割成“页面”,并通过索引获取特定“页面”。例如

    var products = await _context.Products.ToPagedListAsync(pageNumber, pageSize)
    

    【讨论】:

      【解决方案3】:

      我最近受到(复制自)这篇代码项目文章的启发 Entity Framework pagination

      代码:

      public async Task<IList<SavedSearch>> FindAllSavedSearches(int page, int limit)
      {
          if (page == 0)
              page = 1;
      
          if (limit == 0)
              limit = int.MaxValue;
      
          var skip = (page - 1) * limit;
      
          var savedSearches = _databaseContext.SavedSearches.Skip(skip).Take(limit).Include(x => x.Parameters);
          return await savedSearches.ToArrayAsync();
      }
      

      我没有使用实体框架的经验,也没有测试过它的性能,所以请谨慎使用:)

      【讨论】:

        【解决方案4】:

        在 sql server 上非常简单。 你可以写这个查询:

        select count() over(), table.* from table
        

        count() over() 将返回结果中的总行数,因此您不需要运行两个查询.. 请记住,您应该在上下文中运行原始 sql 或使用返回结果作为视图模型的 dapper

        【讨论】:

          【解决方案5】:

          我建议使用 Take() 函数。这可用于指定要从 linq 查询或列表中获取的记录数。例如

          List<customers> _customers = (from a in db.customers select a).ToList();
          var _dataToWebPage = _customers.Take(50);
          

          我在 MVC 应用程序中使用了类似的技术,我将 _customers 列表写入会话,然后在用户单击第 2、3 页等时使用此列表进行进一步的分页查询。这样可以节省多个数据库命中。但是,如果您的列表非常大,那么也将其写入会话可能不是一个好主意。

          对于分页,您可以同时使用 Skip() 和 Take() 函数。例如获取第 2 页的数据:

          var _dataToWebPage = _customers.Skip(50).Take(50);
          

          【讨论】:

          • 谢谢@TimNewton。当然,但是如果我有一百万条记录,或者更好的是一千条记录的数据列非常大,你就会遇到内存不足的异常。
          • Jason,您可以考虑将主键写入会话中的 List 而不是整个对象,然后在每次需要使用主键重新显示数据时从数据库中检索详细信息列表?不过,这仍然需要多次数据库读取。如果您的数据集如此之大,我认为没有多次数据库读取就无法逃脱。
          • 您可能是正确的,无法在 c# 中为此实例读取一个数据库并使用 Linq。我知道这是可以做到的,只是我想要使用 Linq 的能力,因为它是强类型的,并且与我其余的干净代码一起使用。我的分页在不包含大型数据集或大型数据的较小表上工作得很好。
          • Take(50) 之前调用ToList() 意味着您将每条记录拉入您的应用程序。然后,在让服务器完成所有这些工作之后,您将忽略除 50 之外的所有内容。在 ToList() 之前调用 Take(50)
          【解决方案6】:

          显示数百万条记录的常用方法是不显示所有页面。想一想:如果您有数百万条记录,例如每页 20 甚至 100 项,那么您将拥有数万页。 把它们都展示出来是没有意义的。您可以简单地加载当前页面并提供指向下一页的链接,就是这样。 或者您可以加载 100-500 条记录,但仍然只显示一个页面,并使用加载的记录信息为前几页生成页面链接(因此要确定有多少下一页可用)。

          【讨论】:

          • 你说得对,我不想显示成百上千个链接,甚至不想让某人单步浏览那么多页面。我想我遇到的麻烦是我只想写一个查询。例如:MySQL 允许您在一个查询中使用 SQL_CALC_FOUND_ROWS,然后使用另一个查询来提取该结果。很有效率!!!使分页精彩!感谢@VladimirPerevalov 的想法!
          • AFAIK 在 LINQ 中没有这样的支持,在 MS SQL Server 中也没有。实际上,MySql 做了很多事情,而 MS SQL 没有。例如。 SELECT BETWEEN ...对分页也很有效。
          • 您也可以提供文本框“Go To:”和直接跳转到特定页面的按钮。
          • 实际上,显示某种分页器控件来指示页面/项目的总数是很常见的。
          • 例如,@Jonathan Wood 查看来自搜索引擎的结果。它们仅显示约 10 页。和approximate 的总结果数(但这是另一个问题)。
          猜你喜欢
          • 1970-01-01
          • 2022-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多