在实体框架 4.1 中查询一页数据并获取总计数的更好方法?
目前,当我需要运行一个将与分页一起使用的查询时,我会这样做:
//Setup query (Typically much more complex)
var q = ctx.People.Where(p=>p.Name.StartsWith("A"));
//Get total result count prior to sorting
int total = q.Count();
//Apply sort to query
q = q.OrderBy(p => p.Name);
q.Select(p => new PersonResult
{
Name = p.Name
}.Skip(skipRows).Take(pageSize).ToArray();
这有效,但我想知道是否可以在仍然使用 linq 的同时改进它以提高效率?我想不出一种方法可以将计数与数据检索结合到一次数据库访问中,而无需使用存储过程。
Currently when I need to run a query that will be used w/ paging I do it something like this:
//Setup query (Typically much more complex)
var q = ctx.People.Where(p=>p.Name.StartsWith("A"));
//Get total result count prior to sorting
int total = q.Count();
//Apply sort to query
q = q.OrderBy(p => p.Name);
q.Select(p => new PersonResult
{
Name = p.Name
}.Skip(skipRows).Take(pageSize).ToArray();
This works, but I wondered if it is possible to improve this to be more efficient while still using linq? I couldn't think of a way to combine the count w/ the data retrieval in a single trip to the DB w/o using a stored proc.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
以下查询将在一次数据库访问中获取计数和页结果,但如果您检查 LINQPad 中的 SQL,您会发现它不是很漂亮。我只能想象更复杂的查询会是什么样子。
对于像这样的简单查询,您可能可以使用任一方法(2 次访问数据库,或使用
GroupBy
在 1 次行程中完成),并且不会注意到太大的差异。对于任何复杂的事情,我认为存储过程将是最好的解决方案。The following query will get the count and page results in one trip to the database, but if you check the SQL in LINQPad, you'll see that it's not very pretty. I can only imagine what it would look like for a more complex query.
For a simple query like this, you could probably use either method (2 trips to the database, or using
GroupBy
to do it in 1 trip) and not notice much difference. For anything complex, I think a stored procedure would be the best solution.Jeff Ogata 的答案可以稍微优化一下。
这几乎做了同样的事情,只是它不会用不必要的 GROUP BY 来打扰数据库。当您不确定查询将至少包含一个结果,并且不希望它抛出异常时,您可以通过以下方式(尽管不太干净)获取totalCount
:变体:
Jeff Ogata's answer can be optimized a little bit.
This does pretty much the same thing except it won't bother the database with an unnecessary GROUP BY. When you are not certain your query will contain at least one result, and don't want it to ever throw an exception, you can get
totalCount
in the following (albeit less cleaner) way:And the async variant:
对于使用 EF Core >= 1.1.x && 的用户的重要说明< 3.0.0:
当时我正在寻找此问题的解决方案,并且此页面在 Google 术语“EF Core Paging Total Count”中排名第一。
检查 SQL 探查器后我发现 EF 为返回的每一行生成一个
SELECT COUNT(*)
。我已经厌倦了此页面上提供的每个解决方案。这是使用 EF Core 2.1.4 和 EF Core 2.1.4 进行测试的。 SQL Server 2014。最后我不得不将它们作为两个单独的查询来执行,如下所示。至少对我来说,这并不是世界末日。
EF Core 团队似乎已经意识到这一点:
https://github.com/aspnet/EntityFrameworkCore /问题/13739
https://github.com/aspnet/EntityFrameworkCore/issues/11186
Important Note for People using EF Core >= 1.1.x && < 3.0.0:
At the time I was looking for solution to this and this page is/was Rank 1 for the google term "EF Core Paging Total Count".
Having checked the SQL profiler I have found EF generates a
SELECT COUNT(*)
for every row that is returned. I have tired every solution provided on this page.This was tested using EF Core 2.1.4 & SQL Server 2014. In the end I had to perform them as two separate queries like so. Which, for me at least, isn't the end of the world.
It looks like the EF Core team are aware of this:
https://github.com/aspnet/EntityFrameworkCore/issues/13739
https://github.com/aspnet/EntityFrameworkCore/issues/11186
我建议对第一页进行两次查询,一次查询总数,一次查询第一页或结果。
缓存总计数,以便在您超出第一页时使用。
I suggest making two queries for the first page, one for the total count and one for the first page or results.
Cache the total count for use as you move beyond the first page.