使用 NHibernate + Linq + Future 计数 [英] Getting count with NHibernate + Linq + Future
问题描述
我想在编写 Linq 查询时使用 NHibernate 进行分页.做这样的事情很容易:
I want to do paging with NHibernate when writing a Linq query. It's easy to do something like this:
return session.Query<Payment>()
.OrderByDescending(payment => payment.Created)
.Skip((page - 1)*pageSize)
.Take(pageSize)
.ToArray();
但是有了这个,我没有得到任何关于项目总数的信息.如果我只做一个简单的 .Count(),就会生成一个对数据库的新调用.
But with this I don't get any info about the total number of items. And if I just do a simple .Count(), that will generate a new call to the database.
我发现 这个答案 解决了它通过使用未来.但它使用标准.我怎样才能用 Linq 做到这一点?
I found this answer which solved it by using future. But it uses Criteria. How can I do this with Linq?
推荐答案
在 LINQ 中使用 Futures 的困难在于像 Count 这样的操作会立即执行.
The difficulty with using Futures with LINQ is that operations like Count execute immediately.
正如@vandalo 发现的那样,ToFuture()
之后的 Count()
实际上在内存中运行 Count,这很糟糕.
As @vandalo found out, Count()
after ToFuture()
actually runs the Count in memory, which is bad.
在未来的 LINQ 查询中获取计数的唯一方法是在不变字段中使用 GroupBy
.一个不错的选择是已经包含在过滤器中的内容(例如IsActive"属性)
The only way to get the count in a future LINQ query is to use GroupBy
in an invariant field. A good choice would be something that is already part of your filters (like an "IsActive" property)
以下示例假设您在 Payment 中有这样的属性:
Here's an example assuming you have such a property in Payment:
//Create base query. Filters should be specified here.
var query = session.Query<Payment>().Where(x => x.IsActive == 1);
//Create a sorted, paged, future query,
//that will execute together with other statements
var futureResults = query.OrderByDescending(payment => payment.Created)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToFuture();
//Create a Count future query based on the original one.
//The paged query will be sent to the server in the same roundtrip.
var futureCount = query.GroupBy(x => x.IsActive)
.Select(x => x.Count())
.ToFutureValue();
//Get the results.
var results = futureResults.ToArray();
var count = futureCount.Value;
当然,另一种选择是进行两次往返,这无论如何也不错.你仍然可以重用原来的 IQueryable,当你想在更高层做分页时,这很有用:
Of course, the alternative is doing two roundtrips, which is not that bad anyway. You can still reuse the original IQueryable, which is useful when you want to do paging in a higher-level layer:
//Create base query. Filters should be specified here.
var query = session.Query<Payment>();
//Create a sorted, paged query,
var pagedQuery = query.OrderByDescending(payment => payment.Created)
.Skip((page - 1) * pageSize)
.Take(pageSize);
//Get the count from the original query
var count = query.Count();
//Get the results.
var results = pagedQuery.ToArray();
更新 (2011-02-22):我写了一个 博客文章 关于这个问题和更好的解决方案.
Update (2011-02-22): I wrote a blog post about this issue and a much better solution.
这篇关于使用 NHibernate + Linq + Future 计数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!