NHibernate 3 подкачки и определения общего количества строк - PullRequest
12 голосов
/ 20 июля 2011

Я где-то читал (не могу вспомнить, где и как), что NHibernate 3 позволяет определять общее количество записей при выполнении постраничного запроса (в одном запросе к базе данных).Это правильно?

У меня есть этот код:

public IEnumerable<X> GetOrganisms(int PageSize, int Page, out int total)
{
    var query = (from e in Session.Query<X>() select e).AsQueryable();

    return query.Skip((Page - 1) * PageSize).Take(PageSize).ToList();
}

и я хотел бы инициализировать 'total' как можно более эффективно.

Спасибо.

Кристиан

PS:

Потенциальное «решение»?:

Total = (int) Session.CreateCriteria<X>()
.SetProjection(Projections.RowCount())
.FutureValue<Int32>().Value;

var query = (from e in Session.Query<X>() select e).AsQueryable();

return query.Skip((Page - 1) * PageSize).Take(PageSize).ToList();

Ответы [ 3 ]

24 голосов
/ 20 июля 2011

Ваше потенциальное решение будет обработано в одной транзакции, но будет два вызова в дБ. Если у вас должен быть только один вызов БД, вы должны использовать запрос с несколькими запросами / в будущем, как это было предложено коллегами. Для получения дополнительной информации о будущем синтаксисе, проверьте этот пост: http://ayende.com/blog/3979/nhibernate-futures.

Вот несколько способов реализовать ваш сценарий ...

QueryOver (вызовы 2 дБ):
var query = session.QueryOver<Organism>();
var result = query
    .Skip((Page - 1) * PageSize)
    .Take(PageSize)
    .List();
var rowcount = query.RowCount();

С набором образцов из 100 организмов и запросом для организмов 11-20, вот два запроса, отправленных в базу данных:

SELECT TOP (@p0) Id0_0_, Title0_0_ FROM (SELECT this_.Id as Id0_0_, this_.Title as Title0_0_, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM Organism this_) as query WHERE query.__hibernate_sort_row > @p1 ORDER BY query.__hibernate_sort_row;@p0 = 10 [Type: Int32 (0)], @p1 = 10 [Type: Int32 (0)]
SELECT count(*) as y0_ FROM Organism this_
QueryOver (вызов 1 дБ с Future):
var query = session.QueryOver<Organism>()
    .Skip((Page - 1) * PageSize)
    .Take(PageSize)
    .Future<Organism>();
var result = query.ToList();
var rowcount = session.QueryOver<Organism>()
    .Select(Projections.Count(Projections.Id()))
    .FutureValue<int>().Value;

Запрос к тому же набору данных, что и раньше, это сгенерированный запрос:

SELECT TOP (@p0) Id0_0_, Title0_0_ FROM (SELECT this_.Id as Id0_0_, this_.Title as Title0_0_, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM Organism this_) as query WHERE query.__hibernate_sort_row > @p1 ORDER BY query.__hibernate_sort_row;SELECT count(this_.Id) as y0_ FROM Organism this_;;@p0 = 10 [Type: Int32 (0)], @p1 = 10 [Type: Int32 (0)]
Критерии (вызов на 1 дБ с Future):
var criteria = session.CreateCriteria<Organism>()
    .SetFirstResult((Page - 1) * PageSize)
    .SetMaxResults(PageSize)
    .Future<Organism>();
var countCriteria = session.CreateCriteria<Organism>()
    .SetProjection(Projections.Count(Projections.Id()))
    .FutureValue<int>().Value;

Опять же, запрашивая тот же набор данных, критерии с будущими результатами в том же запросе:

SELECT TOP (@p0) Id0_0_, Title0_0_ FROM (SELECT this_.Id as Id0_0_, this_.Title as Title0_0_, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM Organism this_) as query WHERE query.__hibernate_sort_row > @p1 ORDER BY query.__hibernate_sort_row;SELECT count(this_.Id) as y0_ FROM Organism this_;;@p0 = 10 [Type: Int32 (0)], @p1 = 10 [Type: Int32 (0)]

Обратите внимание, что все три стиля запроса приводят к одинаковым точным запросам. Будущий синтаксис просто позволяет NHibernate сделать один вызов базы данных, а не два.

Если вы используете NHibernate 3, я думаю, что самый элегантный способ справиться с этим - использовать новый синтаксис QueryOver. (Вы использовали старый синтаксис NHibernate.Linq в предложенном решении. Вместо этого лучше изучить синтаксис QueryOver.)

3 голосов
/ 30 января 2015

У меня недостаточно репутации, чтобы комментировать решение CodeProgression, описанное выше ... но правильный ОДИН вызов БД с использованием QueryOver w / Future <>:

var query = session.QueryOver<Organism>()
    .Skip((Page - 1) * PageSize)
    .Take(PageSize)
    .Future<Organism>();
// var result = query.ToList();
var rowcount = session.QueryOver<Organism>()
    .Select(Projections.Count(Projections.Id()))
    .FutureValue<int>().Value;
var result = query.ToList();
int iRowCount = rowcount.Value();

Как только вы выполните .ToList () - он попадет в базу данных. Таким образом, вам придется снова нажать на базу данных, чтобы получить rowCount ... который побеждает цель Future <>. Сделайте свой ToList () ПОСЛЕ того, как вы выполнили все ваши запросы. Future <>.

2 голосов
/ 20 июля 2011

Я не думаю, что nhibernate «понимает» значение любого запроса, который он выполняет, поэтому определение общего количества строк не является стандартным запросом.

Самый эффективный способ получить количество строк - это фьючерсы или IMultiQuery (чтобы получить все результаты за один раунд-скрипт в базу данных)

nhibernate-futures

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...