Сложность использования Futures с LINQ заключается в том, что такие операции, как Count, выполняются немедленно.
Как выяснил @vandalo, Count()
после ToFuture()
фактически запускает счетчик в памяти, что плохо.
Единственный способ получить счетчик в будущем запросе LINQ - это использовать GroupBy
в инвариантном поле. Хороший выбор - это то, что уже является частью ваших фильтров (например, свойство IsActive)
Вот пример, предполагающий, что у вас есть такое свойство в 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, что полезно, когда вы хотите выполнить подкачку на более высоком уровне:
//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): я написал сообщение в блоге об этой проблеме и гораздо лучшем решении.