2011-07-20 35 views
11

我已經閱讀了某處(不能記住在哪裏以及如何)NHibernate 3允許在執行分頁查詢(在一個數據庫查詢中)時確定總記錄數。這是正確的嗎?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(); 
} 

,並想初始化的「合計」儘可能高效。

謝謝。

基督教

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

回答

23

你潛在的解決方案將在一個事務中進行處理,但將是兩個數據庫調用。如果您必須只有一個數據庫調用,則應該使用多點查詢/將來查詢作爲對等建議。有關未來語法的更多信息,請查看此帖: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)] 
標準(與Future1分貝呼叫):
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)] 

請注意, e查詢樣式導致相同的查詢。未來的語法只允許NHibernate進行一次數據庫調用而不是兩次。

如果您使用的是NHibernate 3,我認爲最優雅的方式是使用新的QueryOver語法。 (你在你提出的解決方案中使用了舊的NHibernate.Linq語法,你最好學習QueryOver語法。)

+1

可能值得注意的是,兩者是否導致單個查詢是由方言特定的優化驅動的。例如在SQLite上發出兩個查詢,但行爲是相同的(所有的期貨儘可能少地查詢) – AlexCuse

2

我不認爲NHibernate的 '實現' 它執行的任何查詢的意思,所以決定總數行不是標準查詢。

最有效的方式來獲得行計數是期貨或IMultiQuery(以獲得一個roundtript到數據庫的結果)

nhibernate-futures

+0

我已經添加了一些內容,請參閱PS。這是你指的是什麼,這個查詢將在一個數據庫轉換?謝謝。 – cs0815

3

我沒有足夠的聲譽以上CodeProgression的解決方案發表評論......但使用QueryOver適當ONE DB調用W /未來<>是:

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