2011-07-20 10 views
11

Przeczytałem gdzieś (nie pamiętam gdzie i jak), że NHibernate 3 pozwala na określenie całkowitej liczby rekordów podczas wykonywania kwerendy stronicowanej (w jednym zapytaniu do bazy danych). Czy to jest poprawne?NHibernate 3 stronicowanie i określanie całkowitej liczby wierszy

mam ten kod:

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

i chciałby zainicjować 'ogółem' tak skutecznie, jak to możliwe.

Dzięki.

Christian

PS:

Potential 'rozwiązanie' ?:

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

Odpowiedz

23

Twój potencjał rozwiązaniem będą obsługiwane w ramach jednej transakcji, ale będą dwie wywołania db. Jeśli musisz mieć tylko jedno wywołanie db, powinieneś użyć kwerendy wielowątkowej/przyszłej, zgodnie z sugestią peer. Aby uzyskać więcej informacji na temat przyszłej składni, sprawdź ten wpis: http://ayende.com/blog/3979/nhibernate-futures.

Oto kilka sposobów, aby osiągnąć swój scenariusz ... (połączenia 2 db)

QueryOver:
var query = session.QueryOver<Organism>(); 
var result = query 
    .Skip((Page - 1) * PageSize) 
    .Take(PageSize) 
    .List(); 
var rowcount = query.RowCount(); 

Z zestawu próbek 100 organizmach, a odpytywanie dla organizmów 11-20 , tutaj są dwa zapytania wysyłane do dB:

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 wywołania db z przyszłości):
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; 

Pytanie o tych samych danych, jak poprzednio, jest to zapytanie, które są generowane:

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)] 
kryteria (1 połączenie dB w przyszłości)
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; 

Ponownie zapytań dla ten sam zestaw danych, kryteria z przyszłymi wynikami w tym samym zapytaniu:

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

Zauważ, że wszystkie Style zapytań skutkują dokładnie tymi samymi zapytaniami. Przyszła składnia po prostu pozwala NHibernate na wykonanie jednego wywołania bazy danych zamiast dwóch.

Jeśli używasz NHibernate 3, myślę, że najbardziej eleganckim sposobem radzenia sobie z tym jest użycie nowej składni QueryOver. (Użyłeś starej składni NHibernate.Linq w swoim proponowanym rozwiązaniu, zamiast tego lepiej nauczyć się składni QueryOver.)

+1

Prawdopodobnie warto zauważyć, że to, czy te dwie wartości są wynikiem pojedynczego zapytania, zależy od optymalizacji zależnych od dialektu. Na przykład w SQLite są wydawane dwa zapytania, ale zachowanie jest takie samo (wszystkie transakcje futures są wykonywane jednocześnie w jak najmniejszej ilości zapytań) – AlexCuse

2

Nie sądzę NHibernate 'realizuje' sens jakiegokolwiek zapytania to wykonuje, więc określić całkowitą liczbę wiersze nie są standardowo wyszukiwane.

Najbardziej skutecznym sposobem, aby uzyskać liczbę wierszy jest z kontraktami lub IMultiQuery (aby uzyskać wszystkie wyniki w jednym roundtript do bazy danych)

nhibernate-futures

+0

Dodałem coś, zobacz PS. Czy to jest to, do czego się odnosisz i czy to zapytanie zostanie wykonane w jednym db trans? Dzięki. – cs0815

3

nie mam wystarczającej reputacji komentować rozwiązania CodeProgression za wyżej ... ale prawidłowe wezwanie ONE DB używając QueryOver w/Future <> to:

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

Po wykonać .ToList () - To trafi do bazy danych. Musisz więc ponownie trafić do bazy danych, aby uzyskać wartość rowCount ... Która pokonuje cel Future <>. Zrób to ToList() PO zrobisz wszystkie twoje. .Future <> zapytania.

Powiązane problemy