Hibernate有點變態可是又無敵的用法

在項目中有這個一個需求,查詢一個表,顯示爲datagrid,可是須要顯示的一列是個關聯表中的信息,是一對多的,可是須要把這個‘多’以逗號分隔顯示在這一列上。spring

舉例:sql

A1表                      A2表數據庫

id  name                 id  A1_id  namejson

1   name1              1        1     A2_name1ide

2   name2              2        1    A2_name2  this

                 3        2    A2_name3spa

查詢後獲得的顯示在頁面上的datagrid 應該爲:hibernate

id      name      A2_nameorm

1      name1     A2_name1, A2_name2  xml

2      name2      A2_name3

若是用hibernate你會怎麼作呢? 寫sql語句,一個sql能直接寫出這樣的結果的sql嗎? 我想了一下,很難,由於顯示結果須要改變 A2表的維度,須要將關聯的多條記錄轉化爲 一條記錄上的一列的值。有人說實話存儲過程吧, 若是用存儲過程了,那hibernate就失去了使用它的意義,在數據庫移植上就會有問題。咱們的原則是指作基本的sql處理,其餘的都是業務邏輯代替。有人說,用hibernate查詢A1表,而後獲得結果的List,而後遍歷這個List,拿到A1的id,關聯查詢A2表,或者A2的結果集,而後遍歷A2,將A2的那麼拼成字符串,而後構建新的Map對象,將A1的結果集的數據全都加入,而後將構建好的A2關聯信息的以逗號分隔的字符串,加入到Map的一個列中去。 嗯,這樣能夠實現咱們最終要的結果,可是,hibernate得到的結果集List,hibernate自己就須要循環jdbc的Resultset,而後將數據填充到實體對象或者Map對象當中去,而後組織成一個List對象。 而後你又須要再次遍歷這個List對象,講全部的數據取出來,關聯查詢,再從新組織成一個新的Map對象。 數據量小,列比較少,還能夠將就,可是數據量大,列大,又該如何? 研究了一上午hibernate的方法,好像就沒有這麼幹的。不知道hibernate是否原本就能夠支持。 若是hibernate自己就有辦法支持的話,請知道的朋友告知。 最後沒招,就研究了hibernate的Transformers 並讀了AliasedTupleSubsetResultTransformer的源代碼,因而有了點子。我重寫了AliasedTupleSubsetResultTransformer,代碼以下:

  
  
  
  
  1. public class XKAliasToBeanResultTransformer extends AliasedTupleSubsetResultTransformer  
  2. {  
  3.     /**  
  4.      *   
  5.      */  
  6.     private static final long serialVersionUID = 5967847763983844234L;  
  7.  
  8.     private final Class<?> resultClass;  
  9.     private boolean isInitialized;  
  10.     private String[] aliases;  
  11.     private Setter[] setters;  
  12.  
  13.     public XKAliasToBeanResultTransformer(Class<?> resultClass)  
  14.     {  
  15.         if (resultClass == null)  
  16.         {  
  17.             throw new IllegalArgumentException("resultClass cannot be null");  
  18.         }  
  19.         isInitialized = false;  
  20.         this.resultClass = resultClass;  
  21.     }  
  22.  
  23.     /**  
  24.      * {@inheritDoc}  
  25.      */  
  26.     public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength)  
  27.     {  
  28.         return false;  
  29.     }  
  30.  
  31.     public Object transformTuple(Object[] tuple, String[] aliases)  
  32.     {  
  33.         Object result;  
  34.  
  35.         if (!isInitialized)  
  36.         {  
  37.             initialize(aliases);  
  38.         }  
  39.         else  
  40.         {  
  41.             check(aliases);  
  42.         }  
  43.  
  44.         // 關鍵代碼  
  45.         result = Initialization.getInstance().getApplicationContext().getBean(resultClass);  
  46.  
  47.         for (int i = 0; i < aliases.length; i++)  
  48.         {  
  49.             if (setters[i] != null)  
  50.             {  
  51.                 setters[i].set(result, tuple[i], null);  
  52.             }  
  53.         }  
  54.  
  55.         return result;  
  56.     }  
  57.  
  58.     private void initialize(String[] aliases)  
  59.     {  
  60.         PropertyAccessor propertyAccessor = new ChainedPropertyAccessor(new PropertyAccessor[] { PropertyAccessorFactory.getPropertyAccessor(resultClass, null),  
  61.                 PropertyAccessorFactory.getPropertyAccessor("field") });  
  62.         this.aliases = new String[aliases.length];  
  63.         setters = new Setter[aliases.length];  
  64.         for (int i = 0; i < aliases.length; i++)  
  65.         {  
  66.             String alias = aliases[i];  
  67.             if (alias != null)  
  68.             {  
  69.                 this.aliases[i] = alias;  
  70.                 setters[i] = propertyAccessor.getSetter(resultClass, alias);  
  71.             }  
  72.         }  
  73.         isInitialized = true;  
  74.     }  
  75.  
  76.     private void check(String[] aliases)  
  77.     {  
  78.         if (!Arrays.equals(aliases, this.aliases))  
  79.         {  
  80.             throw new IllegalStateException("aliases are different from what is cached; aliases=" + Arrays.asList(aliases) + " cached=" + Arrays.asList(this.aliases));  
  81.         }  
  82.     }  
  83.  
  84.     public boolean equals(Object o)  
  85.     {  
  86.         if (this == o)  
  87.         {  
  88.             return true;  
  89.         }  
  90.         if (o == null || getClass() != o.getClass())  
  91.         {  
  92.             return false;  
  93.         }  
  94.  
  95.         XKAliasToBeanResultTransformer that = (XKAliasToBeanResultTransformer) o;  
  96.  
  97.         if (!resultClass.equals(that.resultClass))  
  98.         {  
  99.             return false;  
  100.         }  
  101.         if (!Arrays.equals(aliases, that.aliases))  
  102.         {  
  103.             return false;  
  104.         }  
  105.  
  106.         return true;  
  107.     }  
  108.  
  109.     public int hashCode()  
  110.     {  
  111.         int result = resultClass.hashCode();  
  112.         result = 31 * result + (aliases != null ? Arrays.hashCode(aliases) : 0);  
  113.         return result;  
  114.     }  

上面「關鍵代碼」的地方,原來的代碼,只是resultClass.newInstance(); 個人修改其實很簡單,就是使用spring的Context獲取的bean而已,這樣bean就能夠被加強了,能夠注入,能夠支持事務了。因而,咱們就能夠在hibernate像實體對象填充數據的時機作任何的事情,包括我上面的需求,一旦hibernate像實體對象填充數據,就要調用set方法,在調用setId這個方法的時候,咱們就能得到每條記錄的id,而後能夠查詢關聯表,組織處以逗號分隔的關聯表多條記錄的名稱,而後填充到實體對象的某一個屬性上。這樣,查詢完畢,咱們得到的List中的實體對象,就已經包含了咱們要的多表合併出的那列的值,咱們只用json一下,返回前臺,輕鬆的就能夠在datagrid上顯示出咱們要的結果。

這樣作的壞處,目前看只有一條,就是沒法應對hibernate的升級,若是升級變更大,就須要修改調整代碼了。

若是有朋友有更好的辦法,能夠提出交流,個人這種辦法,有點簡單粗暴,可是能夠應對一切不可能完成的任務。 其實說白了,至關於在hibernate給實體對象填充數據的過程當中攔截。

相關文章
相關標籤/搜索