Hibernate一直都認為比較簡單 就那么影射一下:)但最近項目當中遇見很多問題,今天看見別人在項目當中使用了 Hibernate3的DetachedCriteria,感覺真的是太好了,于是就花了點時間研究了一下,希望和大家分享一下吧
            針對這種需求,對于分層應用程序來說,Web層需要傳遞一個查詢的條件列表給業務層對象,業務層對象獲得這個條件列表之后,然后依次取出條件,構造查詢語句。這里的一個難點是條件列表用什么來構造?傳統上使用Map,但是這種方式缺陷很大,Map可以傳遞的信息非常有限,只能傳遞name和value,無法傳遞究竟要做怎樣的條件運算,究竟是大于,小于,like,還是其它的什么,業務層對象必須確切掌握每條entry的隱含條件。因此一旦隱含條件改變,業務層對象的查詢構造算法必須相應修改,但是這種查詢條件的改變是隱式約定的,而不是程序代碼約束的,因此非常容易出錯。

            DetachedCriteria可以解決這個問題,即在web層,程序員使用DetachedCriteria來構造查詢條件,然后將這個DetachedCriteria作為方法調用參數傳遞給業務層對象。而業務層對象獲得DetachedCriteria之后,可以在session范圍內直接構造Criteria,進行查詢。就此,查詢語句的構造完全被搬離到web層實現,而業務層則只負責完成持久化和查詢的封裝即可,與查詢條件構造完全解耦,非常完美!這恐怕也是以前很多企圖在web層代碼中構造HQL語句的人想實現的夢想吧!

            示例代碼片段如下:

            web層程序構造查詢條件:

            
          Java代碼:
          DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Department.class);
          detachedCriteria.add(Restrictions.eq("name", "department")).createAlias("employees", "e").add(Restrictions.gt(("e.age"), new Integer(20)));


            Department和Employee是一對多關聯,查詢條件為:

            名稱是“department”開發部門;
            部門里面的雇員年齡大于20歲;

            業務層對象使用該條件執行查詢:

            java代碼: detachedCriteria.getExecutableCriteria(session).list();

            最大的意義在于,業務層代碼是固定不變的,所有查詢條件的構造都在web層完成,業務層只負責在session內執行之。這樣代碼就可放之四海而皆準,都無須修改了。

            然而Spring和Hibernate3的DetachedCriteria有不兼容的問題,因此在Spring環境下面使用Hibernate3需要注意:

            Spring的HibernateTemplate提供了Hibernate的完美封裝,即通過匿名類實現回調,來保證Session的自動資源管理和事務的管理。其中核心方法是:

            java代碼:
          HibernateTemplate.execute(new HibernateCallback() {
           public Object doInHibernate(Session session) throws HibernateException {
            ....
           }
          }

            回調方法提供了session作為參數,有了session,就可以自由的使用Hibernate API編程了。使用了spring的之后,代碼修改如下:

            web層代碼:

            java代碼:
          DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Department.class);
          detachedCriteria.createAlias("employees", "e").add(Restrictions.eq("name", "department")).add(Restrictions.gt(("e.age"), new Integer(20)));
          departmentManager.findByCriteria(detachedCriteria);

            構造detachedCriteria,作為參數傳遞給departmentManager

            業務層代碼使用spring,DepartmentManager的findByCriteria如下:

            java代碼:

          public List findByCriteria(final DetachedCriteria detachedCriteria) {
           return (List) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException {
             Criteria criteria = detachedCriteria.getExecutableCriteria(session);
             return criteria.list();
            }
           });
          }

            實際上也就是:

            java代碼:
          Criteria criteria = detachedCriteria.getExecutableCriteria(session);
          return criteria.list();

            而已

            但是該程序代碼執行,會拋出強制類型轉換異常!

            我跟蹤了一下spring和Hibernate源代碼,原因如下:

            spring的HibernateTemplate的execute方法提供的回調接口具有Session作為參數,但是實際上,默認情況下,HibernateTemplate傳遞給回調接口的session并不是org.hibernate.impl.SessionImpl類,而是SessionImpl類的一個Proxy類。之所以替換成為一個Proxy類,HibernateTemplate的注釋說明,Proxy提供了一些額外的功能,包括自動設置Cachable,Transaction的超時時間,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) {
           impl.setSession( (SessionImpl) session ); // 要求SessionImpl,Spring傳遞的是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 = detachedCriteria.getExecutableCriteria(session);
             return criteria.list();
            }
           }, true);
          }
          posted on 2007-12-22 02:44 LifeNote 閱讀(1504) 評論(4)  編輯  收藏 所屬分類: JavaHibernate
          Comments
          • # re: Hibernate3 的DetachedCriteria 學習
            nanako
            Posted @ 2007-12-22 14:36
            你這樣做出會不會使web層和持久層耦合  回復  更多評論   
          • # re: Hibernate3 的DetachedCriteria 學習
            LifeNote
            Posted @ 2007-12-22 16:17
            是的 只是弄一個例子 看看這個怎么用的   回復  更多評論   
          • # re: Hibernate3 的DetachedCriteria 學習[未登錄]
            netfishx
            Posted @ 2007-12-22 19:52
            這樣用根本就是反模式啊  回復  更多評論   
          • # re: Hibernate3 的DetachedCriteria 學習[未登錄]
            John
            Posted @ 2008-01-03 11:06
            在web layer就用上了hibernate,是強耦合。  回復  更多評論   
           
          主站蜘蛛池模板: 铜陵市| 太原市| 静海县| 万载县| 大新县| 紫云| 铜山县| 新津县| 香港 | 东至县| 沙湾县| 贵州省| 奇台县| 沙雅县| 犍为县| 姜堰市| 寻甸| 景德镇市| 江阴市| 大新县| 土默特左旗| 大埔区| 衢州市| 葵青区| 塔河县| 齐河县| 隆林| 定南县| 绥中县| 徐汇区| 邻水| 白银市| 关岭| 贺兰县| 五河县| 开鲁县| 衡水市| 华宁县| 凤山县| 清丰县| 怀安县|