Sparta Yew

               簡約、職業(yè)、恒久
          隨筆 - 15, 文章 - 1, 評論 - 276, 引用 - 0
          數(shù)據(jù)加載中……

          Hibernate3查詢返回Map探秘


              -源于我對它的一個誤會

              sparta-紫杉 2010-4-14 9:02 

              開發(fā)環(huán)境: eclipse3.4.2 + weblogic10.3 + jdk1.6.0_13 + Struts2.1.8 + Spring3.0.1 + Hiberante3.3.2

              初識Hibernate3的查詢結(jié)果返回Map的功能是非常高興的,因為我第一印象認(rèn)為它能夠解決類似以下的問題:

              從角色表SysRoles中,得到以Role_Id(角色ID)為Key, 以Role_Desc(角色描述)為Value的Map。

              要知道在以前,我通常采用如下的傳統(tǒng)方式解決此類問題:

          public HashMap getRolesMap(){
                  
          try {

                          List
          <SysRoles> results =  getHibernateTemplate().find("from SysRoles");

                          Map hashMap 
          = new HashMap(0);
                      
                      
          for( SysRoles role : results ){
                              hashMap.put( role.getRoleId(), role.getRoleDesc());
                          }


                          
          return hashMap;
                  }
           catch (RuntimeException re) {

                          
          throw re;
                  }

              }

               代碼雖也不多,短短5行代碼,但在代碼里面需要經(jīng)過一次提取,一次加工的過程也有點繁瑣,程序員嘛,要本著一個“代碼簡潔、清晰”的原則。

              有無更好的方法呢?那么在知道Hibernate3能夠從查詢結(jié)果中返回Map的功能后,我很自然的寫下如下的代碼,以為能節(jié)省一個加工的過程:

          public HashMap getPermissionMap(){
                  
          try {    

                          HashMap hashMap 
          = (HashMap)getSession()
                                  .createSQLQuery(
          "select role_Id, role_Desc  from Sys_Roles").setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
                      
                          
          return hashMap;
                  }
           catch (RuntimeException re) {

                          
          throw re;
                  }

              }


          哈哈,只有兩行代碼便能解決這種問題,看起來似乎是理想的選擇,趕快試試吧。

          運行后,在jsp偌大的空白頁面上,一行異常代碼分外刺眼: org.hibernate.impl.SQLQueryImpl cannot be cast to java.util.HashMap.

          看來setResultTransformer是不能直接返回Map的,它是返回一個封裝了所有Map的List。

          看來我還真是太草率了,對上面語句中的“Transformers.ALIAS_TO_ENTITY_MAP”迷感了雙眼。

          看來事情并不那么簡單,還需要探索,既然已經(jīng)開始了,索性探索個明白吧!在經(jīng)過對代碼、對查詢方法進行幾次修訂后,成為如下代碼:

          public HashMap getPermissionMap(){
                  
          try {
                      
                           List list 
          = getHibernateTemplate()
                                           .find(
          "select new Map(sysRoles.roleId as roleId, sysRoles.roleDesc as roleDesc) from SysRoles sysRoles");

                      
          for( Object map : list){
                               hashMap.putAll( (Map) map );

                           }


                           
          return (HashMap) hashMap;
                  }
           catch (RuntimeException re) {

                          
          throw re;
                  }

              }


              修改完成之后,我不禁啞然失笑,之前堅持的所謂的“代碼簡潔、清晰”原則已經(jīng)蕩然無存。但反觀代碼,似乎有些道理,同時,對java的使用也有了更進一步的理解,對浪費的時光也不再那么憐惜了。

              可惜事情總不能如你所愿,通過對代碼的執(zhí)行發(fā)現(xiàn),數(shù)據(jù)庫里面有多條數(shù)據(jù),但是那個返回的hashMap的size卻始終是一條。

              我通過下面代碼對返回的hashMap進行循環(huán)打印,發(fā)現(xiàn)僅能打印一條,并且內(nèi)容始終是一樣:

          for( Map.Entry map : hashMap.entrySet() ){
                  System.out.println(
          "#### map1.getKey() = " + map1.getKey() + ", map1.getValue()=" + map1.getValue());
          }


          唉,還是找找相關(guān)的“從Hibernate的查詢結(jié)果中返回Map”的原理吧,看來我們多少得為我們的草率付出點代價。

          下面是我從Hibernate的教程中得到的相關(guān)信息,一個說得比較清楚的是javaEye(現(xiàn)在為itEye)的蔡華江,請原諒使用了你的文章:


          //////////////////////////////////////////////////// 摘抄開始 ///////////////////////////////////////////

          在問答里和論壇中,經(jīng)??吹接腥藛?,怎樣將使用本地SQL查詢出來的結(jié)果映射為值對象的問題,這里就Hibernate中提供的方法做個結(jié)論。
          前提,這里沒有使用屬性的延遲加載技術(shù)。

          假設(shè)有個值對像,如下:

          package test;

          public class Person {
             
          private Long id;
             
          private String name;
             
          private Long age;
             
          private Long phone;
             
          private String address;

           
          public Person(Long id, String name, Long age, Long phone, String address) {
               
          this.id = id;
               
          this.name = name;
               
          this.age = age;
               
          this.phone = phone;
               
          this.address = address;
                  }


             
          public Long getId() {
               
          return id;
             }


             
          public void setId(Long id) {
               
          this.id = id;
             }


             
          public String getName() {
               
          return name;
             }


             
          public void setName(String name) {
               
          this.name = name;
             }


             
          public Long getAge() {
               
          return age;
             }


             
          public void setAge(Long age) {
               
          this.age = age;
             }


             
          public Long getPhone() {
               
          return phone;
             }


             
          public void setPhone(Long phone) {
               
          this.phone = phone;
             }


             
          public String getAddress() {
               
          return address;
             }


             
          public void setAddress(String address) {
               
          this.address = address;
             }

          }

          如果查詢?nèi)课辶杏涗浀脑挘敲粗灰?/p>

          List list = getHibernateTemplate().loadAll(Person.class);

          如果只需要查詢id,name,age三列記錄呢?那么就要新增構(gòu)造方法了,

          public Person(Long id, String name, Long age) {
                
          this.id = id;
                
          this.name = name;
                
          this.age = age;
          }

          然后呢,就可以通過HQL來進行查詢。

          List list = getHibernateTemplate().find("select new test.Person(id,name,age) from Person");

          這個方法通??梢詽M足需要了,只是如果,只需要查詢id,name,phone三列記錄的話,還新增構(gòu)造方法?不行了,會出現(xiàn)構(gòu)造方法沖突了。有個辦法:

          List list = getSession().createQuery("select id,name,phone from person")
                                      .addScalar(
          "id",Hibernate.Long).addScalar("name").addScalar("phone",Hibernate.Long)
                                      .addEntity(Person.
          class);


          但是,這個只適用于存在Person實體的,如果Hibernate中沒有進行Person映射的呢,系統(tǒng)中只存在一個JavaBean。

          List list = getSession().createSQLQuery("select id \"id\",name \"name\",phone \"phone\" from person")
                                  .addScalar(
          "id",Hibernate.Long).addScalar("name").addScalar("phone",Hibernate.Long)
                                  .setResultTransformer(Transformers.aliasToBean(Person.
          class)));


              那么Hibernate就會自動將查出來的三列內(nèi)容組裝到VO對象中去,只是代碼量有點大,而且名稱都需要重新定義為小寫的,在Oracle中查出來的列都默認(rèn)為大寫的(不知道其它數(shù)據(jù)庫怎么樣),這個辦法就不依賴于構(gòu)造方法了,只需要定義私有變量,設(shè)置getter/setter方法就行了。

          不過如果更猛點的,根本就沒有JavaBean對象可以填充怎么辦,Hibernate可以將查出來的列組裝到集合類中去。如Map。

          List list = getSession().createSQLQuery("select * from person")
                     .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);


          //sparta-紫杉 注:這個ALIAS_TO_ENTITY_MAP的含義是指以數(shù)據(jù)庫里的字段為key,以字段內(nèi)容為Value的Map。有幾個字段就會生成幾個Map,然后將所有的Map組裝到List中。

          除了這個Transformers還可以將列轉(zhuǎn)化為List。

          List list = getSession().createSQLQuery("select * from person")
                              .setResultTransformer(Transformers.T0_LIST);


          到此,還可以通過繼承Transformers將結(jié)果映射為其它對象,不累述了,基本功能夠用了。

          //////////////////////////////////////////////////// 摘抄結(jié)束 ///////////////////////////////////////////

              哈哈,各位達(dá)人,看完上面這篇文章之后,豁然開朗了吧?

              請注意在上面文章中筆者注釋的一段文字就會明白:在hibernate從查詢結(jié)果返回Map中,是以字段為key,以字段的內(nèi)容為Value的Map,而不是我想象的假設(shè)我在查詢中僅提供兩個字段,那么Hibernate就會自然地以我的第一個字段的內(nèi)容為key,以第二個字段的內(nèi)容為Value生成Map列表。

              那么我也終于明白為什么在我的執(zhí)行結(jié)果中僅有一條數(shù)據(jù)的原因了,因為在我的代碼中返回的list里面,雖然有很多條數(shù)據(jù),但是我們應(yīng)該明白一點:
          當(dāng)我使用Map的putAll時,由于在Map中,均是以字段名稱作為key的,那么在數(shù)據(jù)庫中無論有多少條的記錄,字段名始終是相同的,也就是說,在Map中重復(fù)的key會被反復(fù)覆蓋,僅保留最后的一條。 它是返回一個封裝了所有Map的List,在使用時,只有迭代該List,提取各Map進行使用才不會導(dǎo)致重復(fù)覆蓋。


              什么樣的應(yīng)用場景賦予我們什么樣的想象力,誤會有時源于無知,但更多源于我們的無限想象力,有時異想天開的靈感確實能為我們提供打開另一扇未知知識大門的鑰匙。
              難道不是嗎? 本次誤會讓我對Hibernate的理解又深入了一層,無論是原理還是應(yīng)用場景。再者,不妨將牛吹大一點吧:希望Hibernate團隊能夠從我的這個誤會中吸取點靈感,開發(fā)出一個能夠返回以前后兩個字段的內(nèi)容分別為key和value的Map的方法來,以方便各位使用Hibernate的程序達(dá)人,似乎也未嘗不可吧? 哈哈!

           

           



                      -東營 sparta-紫杉 原創(chuàng),轉(zhuǎn)載請注明出處 :)
                      http://www.aygfsteel.com/SpartaYew/
                      SpartaYew@163.com
           
                      
          QQ:22086526

          posted on 2011-05-19 08:26 sparta-紫杉 閱讀(14244) 評論(3)  編輯  收藏 所屬分類: SSH2

          評論

          # re: Hibernate3查詢返回Map探秘   回復(fù)  更多評論   

          不錯
          2011-10-17 15:20 | 段凱歌

          # re: Hibernate3查詢返回Map探秘 [未登錄]  回復(fù)  更多評論   

          你居然犯這樣的低等錯誤,而且還寫出個文章,服了你了,有這點時間,不如多研究下其他技術(shù)問題呢
          2015-04-22 13:36 |

          # re: Hibernate3查詢返回Map探秘 [未登錄]  回復(fù)  更多評論   

          “在hibernate從查詢結(jié)果返回Map中,是以字段為key,以字段的內(nèi)容為Value的Map,而不是我想象的假設(shè)我在查詢中僅提供兩個字段,那么Hibernate就會自然地以我的第一個字段的內(nèi)容為key,以第二個字段的內(nèi)容為Value生成Map列表?!?br>
          按你的想法,如果查詢結(jié)果里有一個,三個或以上字段,它要如何映射,太天真了
          2015-04-22 13:39 |
          主站蜘蛛池模板: 昌黎县| 邵阳县| 长泰县| 闽侯县| 富阳市| 衡南县| 上杭县| 应城市| 宝应县| 台中县| 上犹县| 汝南县| 梅州市| 常熟市| 康保县| 乌海市| 丽水市| 克拉玛依市| 吉安市| 盘锦市| 灯塔市| 准格尔旗| 资溪县| 怀来县| 丰都县| 蓝山县| 胶南市| 紫阳县| 息烽县| 涟水县| 美姑县| 南丰县| 广河县| 义乌市| 富顺县| 乐都县| 莫力| 出国| 扎赉特旗| 长泰县| 大渡口区|