最近在做一個項目,資料庫訪問層使用了NHibernate 2.1.0,因為項目中需要使用到分頁取資料的功能,於是在Google上搜了一把如何使用NHibernate來擷取分頁資料。結果還真不少!不過除了介紹Hibernate的,差不多都千篇一律,看來不是某某高手的文章被過度轉載,就是天下文章一大抄啊。先給兩個連結大家可以看看:
http://www.cnblogs.com/scottpei/archive/2009/10/11/1580947.html
http://blog.csdn.net/loyayol/archive/2007/09/26/1802015.aspx
既然大家都認同這個方法,偶就試試吧!
將代碼拷貝到我的工程中,稍作修改以適應項目的需要,然後寫了一個測試頁面運行,出錯了!提示資訊是Value cannot be null. Parameter name: projections 查了一下出錯的代碼,就在crit.SetProjection(null) ;這一行。看來還不能直接傳null值進去。不清楚網上流傳的這個版本大家都試過沒有,明明就不對嘛,不過也有可能跟我所使用的NHibernate版本有關,這個可能在早期的版本中奏效吧。我也查了一下NHibernate 2.1.0的官方版本修改記錄文檔,說是對ICriteria.SetProjection()方法的參數做了一些修改。那這個問題怎麼解決呢?
我嘗試著將這行代碼去掉,結果在最後擷取分頁資料時報SQL語句語法錯誤,仔細看了下代碼,這行的主要用途就是在通過crit.SetProjection(Projections.RowCount()).UniqueResult()方法取得總記錄數後將SetProjection()方法所附加的條件去掉,否則下面繼續使用該對象去擷取分頁資料時就會得到類似於這樣的SQL語句:
Select Top 5 Count(*) From MyTable
這個在資料庫中執行肯定是通不過的。看來在取得分頁資料前必須將SetProjection()方法所附件的條件清除掉,可是查看ICriteria對象下面並沒有提供這樣的方法,SetProjection()方法所附加的條件又不能簡單得去掉。後台看到一篇老外的文章,得到了一些啟發,其實我們可以將ICriteria對象Clone一份,前一個對象專門用來返回總記錄條數,Clone後的對象則專門用來取得分頁資料,這樣問題就可以完美解決了。下面是我整理後的代碼,大家可以參考下。
/// <summary>
/// Get the pagination product list.
/// </summary>
/// <param name="cateId">Product category ID.</param>
/// <param name="currentPageIndex">Current page index, begin with 1.</param>
/// <param name="pageSize">Row count per page.</param>
/// <param name="recordCount">Return the total record count from database.</param>
/// <returns>Return the paged product object list.</returns>
public List<Products> GetProducts(int? cateId, int currentPageIndex, int pageSize, out int recordCount)
{
ICriteria crit = Session.CreateCriteria(typeof(Products));
// Set query condition.
crit.Add(Restrictions.Eq("Isdisabled", true));
if (cateId != null)
{
crit.Add(Restrictions.Eq("Cateid.Id", cateId));
}
// Copy current ICriteria instance to the new one for getting the pagination records.
ICriteria pageCrit = CriteriaTransformer.Clone(crit);
// Get the total record count
recordCount = Convert.ToInt32(crit.SetProjection(Projections.RowCount()).UniqueResult());
//Set pagination
pageCrit.AddOrder(new Order("Createdate", false)); // Set order parameter.
pageCrit.SetFirstResult((currentPageIndex - 1) * pageSize).SetMaxResults(pageSize);
return pageCrit.List<Products>().ToList<Products>();
}
使用CriteriaTransformer.Clone()方法將ICriteria對象Clone一個副本。擷取分頁資料的邏輯仍然使用了網路上流傳的那個版本中的代碼。下面是測試代碼:
ProductBll productBll = new ProductBll();
int recordCount;
List<Products> list = productBll.GetProducts(null, 11, 5, out recordCount);
如果沒有where條件,可以將cateId的值設為null,第二個參數為當前的頁碼,從1開始,第三個參數是每頁要顯示的資料條數,最後一個參數是out類型的,在使用前只需要定義而不必初始化,用來擷取總資料條數。