Hibernate支持DetachedCriteria這是一個非常有意義的特性!我們知道在常規的Web編程中有大量的動態條件查詢即用戶在網頁上面自由選擇某些條件程序根據用戶的選擇條件動態生成SQL語句進行查詢
針對這種需求對於分層應用程序來說Web層需要傳遞一個查詢的條件列表給業務層對象業務層對象獲得這個條件列表之後然後依次取出條件構造查詢語句這裡的一個難點是條件列表用什麼來構造?傳統上使用Map但是這種方式缺陷很大Map可以傳遞的信息非常有限只能傳遞name和value無法傳遞究竟要做怎樣的條件運算究竟是大於小於like還是其它的什麼業務層對象必須確切掌握每條entry的隱含條件因此一旦隱含條件改變業務層對象的查詢構造算法必須相應修改但是這種查詢條件的改變是隱式約定的而不是程序代碼約束的因此非常容易出錯
DetachedCriteria可以解決這個問題即在web層程序員使用DetachedCriteria來構造查詢條件然後將這個DetachedCriteria作為方法調用參數傳遞給業務層對象而業務層對象獲得DetachedCriteria之後可以在session范圍內直接構造Criteria進行查詢就此查詢語句的構造完全被搬離到web層實現而業務層則只負責完成持久化和查詢的封裝即可與查詢條件構造完全解耦非常完美!這恐怕也是以前很多企圖在web層代碼中構造HQL語句的人想實現的夢想吧!
示例代碼片段如下
web層程序構造查詢條件
java代碼
DetachedCriteria detachedCriteria = DetachedCriteriaforClass(Departmentclass);
detachedCriteriaadd(Restrictionseq(name department))createAlias(employees e)add(Restrictionsgt((eage) new Integer()));
Department和Employee是一對多關聯查詢條件為
名稱是department開發部門部門裡面的雇員年齡大於歲
業務層對象使用該條件執行查詢
java代碼
detachedCriteriagetExecutableCriteria(session)list();
最大的意義在於業務層代碼是固定不變的所有查詢條件的構造都在web層完成業務層只負責在session內執行之這樣代碼就可放之四海而皆准都無須修改了
然而Spring和Hibernate的DetachedCriteria有不兼容的問題因此在Spring環境下面使用Hibernate需要注意
Spring的HibernateTemplate提供了Hibernate的完美封裝即通過匿名類實現回調來保證Session的自動資源管理和事務的管理其中核心方法是
java代碼
HibernateTemplateexecute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
}
}
回調方法提供了session作為參數有了session就可以自由的使用Hibernate API編程了使用了spring的之後代碼修改如下
web層代碼
java代碼
DetachedCriteria detachedCriteria = DetachedCriteriaforClass(Departmentclass);
detachedCriteriacreateAlias(employees e)add(Restrictionseq(name department))add(Restrictionsgt((eage) new Integer()));
departmentManagerfindByCriteria(detachedCriteria);
構造detachedCriteria作為參數傳遞給departmentManager
業務層代碼使用springDepartmentManager的findByCriteria如下
java代碼
public List findByCriteria(final DetachedCriteria detachedCriteria) {
return (List) getHibernateTemplate()execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria criteria = detachedCriteriagetExecutableCriteria(session);
return criterialist();
}
});
}
實際上也就是
java代碼
Criteria criteria = detachedCriteriagetExecutableCriteria(session);
return criterialist();
而已
但是該程序代碼執行會拋出強制類型轉換異常!
我跟蹤了一下spring和Hibernate源代碼原因如下
spring的HibernateTemplate的execute方法提供的回調接口具有Session作為參數但是實際上默認情況下HibernateTemplate傳遞給回調接口的session並不是orghibernateimplSessionImpl類而是SessionImpl類的一個Proxy類之所以替換成為一個Proxy類HibernateTemplate的注釋說明Proxy提供了一些額外的功能包括自動設置CachableTransaction的超時時間Session資源的更積極的關閉等等
java代碼
private boolean exposeNativeSession = false;
execute方法內部
Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));
但是遺憾的是Hibernate的DetachedCriteria的setExecutableCriteria方法卻要求將session參數強制轉為SessionImpl但是spring傳過來的卻是一個Proxy類因此就報錯了
java代碼
public Criteria getExecutableCriteria(Session session) {
implsetSession( (SessionImpl) session ); // 要求SessionImplSpring傳遞的是Proxy
return impl;
}
解決方法禁止Spring的HibernateTemplate傳遞Proxy類強制要求它傳遞真實的SessionImpl類即給exexute方法增加一個參數提供參數為true如下
java代碼
public List findByCriteria(final DetachedCriteria detachedCriteria) {
return (List) getHibernateTemplate()execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria criteria = detachedCriteriagetExecutableCriteria(session);
return criterialist();
}
} true);
}
附一個進行模糊查詢的例子
public PaginationSupport findPageByCriteria(int startIndex int pageSize String sortColumnId Boolean bSortOrder final String likeValue) {
DetachedCriteria detachedCriteria = DetachedCriteria forClass(Timeclass);
// like condition
if ((likeValue != null && likeValuetrim()length() > )) {
detachedCriteriaadd(Restrictionsor(RestrictionssqlRestriction(statime like ? % + likeValue + % HibernateSTRING)RestrictionssqlRestriction(endtime like ? % + likeValue + % HibernateSTRING)));
}
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28847.html