问题 C#实体框架分页


有没有办法获得复杂的Linq查询和数百万条记录的行数  点击数据库两次或写2个单独的查询?

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

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


8265
2018-04-13 17:52


起源

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


答案:


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

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);

10
2018-04-16 22:58



谢谢@TimNewton。当然,但是如果我有一百万条记录或更好的数千条带有非常大的数据列的记录,则会遇到内存不足异常。 - Jason Foglia
Jason,您可以考虑在会话中将主键写入List而不是整个对象,然后每次需要使用列表中的主键重新显示数据时从数据库中检索详细信息?这仍然需要多个数据库读取。如果数据集太大,我不认为如果没有多个数据库读取就可以逃脱。 - Tim Newton
你可能是正确的,因为无法在c#中使用Linq对这个实例进行一次db读取。我知道这可以做到,只是因为我希望能够使用Linq,因为它是强类型的,并且与我的其他干净代码一起使用。我的分页在没有大数据集或大数据的小型表上完美运行。 - Jason Foglia
调用 ToList() 之前 Take(50) 意味着您将每条记录都拉入您的应用程序然后,在使服务器完成所有工作之后,你忽略了除了50之外的所有服务 Take(50) 之前 ToList() - mmcrae


显示数百万条记录的常用方法就是不显示所有页面。想一想:如果你有数百万条记录,比如每页20个甚至100个项目,那么你将有数万页。 展示它们是没有意义的。您只需加载当前页面并提供指向下一页的链接即可。 或者您可以加载说100-500条记录,但仍然只显示一个页面并使用加载的记录信息生成前几页的页面链接(因此确切知道有多少下一页可用)。


2
2018-04-13 18:23



你是对的,我不想展示数百或数千个链接,甚至让某人走过那么多页面。我想我遇到的麻烦是我只想写一个查询。例如:MySQL允许您在查询中使用SQL_CALC_FOUND_ROWS,然后使用另一个查询来获取该结果。效率很高!!!制作分页精彩!谢谢@VladimirPerevalov的想法! - Jason Foglia
AFAIK在MSQ Server中既没有LINQ也没有这样的支持。实际上MySql有很多东西,MS SQL没有。例如。 SELECT BETWEEN ... 对分页也很有效。 - Vladimir Perevalov
您还可以提供一个文本框“Go To:”和一个直接跳转到特定页面的按钮。
实际上,显示某种页面控制器指示页面/项目的总数是很常见的。 - Jonathan Wood
@Jonathan Wood看一下搜索引擎的结果。它们只显示约10页。和 approximate 总结果数(但完全是另一个问题)。 - Vladimir Perevalov


在sql server上这么容易。 你可以写这个查询:

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

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


2
2017-09-19 07:05