在遷移原先用JDBC/SQL實現的系統,難免需要采用hibernat native sql支持。
1.使用SQLQuery
hibernate對原生SQL查詢執行的控制是通過SQLQuery接口進行的.

最基本的SQL查詢就是獲得一個標量(數值)的列表。

2

如果要避免過多的使用ResultSetMetadata,或者只是為了更加明確的指名返回值,可以使用addScalar()。

2

3

4

這個查詢指定了:SQL查詢字符串,要返回的字段和類型.它仍然會返回Object數組,但是此時不再使用ResultSetMetdata,而是明確的將ID,NAME和BIRTHDATE按照Long,String和Short類型從resultset中取出。同時,也指明了就算query是使用*來查詢的,可能獲得超過列出的這三個字段,也僅僅會返回這三個字段。
對全部或者部分的標量值不設置類型信息也是可以的。

2

3

4

基本上這和前面一個查詢相同,只是此時使用ResultSetMetaData來決定NAME和BIRTHDATE的類型,而ID的類型是明確指出的。
關于從ResultSetMetaData返回的java.sql.Types是如何映射到Hibernate類型,是由方言(Dialect)控制的。假若某個指定的類型沒有被映射,或者不是你所預期的類型,你可以通過Dialet的registerHibernateType調用自行定義.
1.2 實體查詢
上面的查詢都是返回標量值的,也就是從resultset中返回的“裸”數據。下面展示如何通過addEntity()讓原生查詢返回實體對象。

2

這個查詢指定:SQL查詢字符串,要返回的實體.假設Cat被映射為擁有ID,NAME和BIRTHDATE三個字段的類,以上的兩個查詢都返回一個List,每個元素都是一個Cat實體。 假若實體在映射時有一個many-to-one的關聯指向另外一個實體,在查詢時必須也返回那個實體,否則會導致發生一個"column not found"的數據庫錯誤。這些附加的字段可以使用*標注來自動返回,但我們希望還是明確指明,看下面這個具有指向Dog的many-to-one的例子:

1.3 處理關聯和集合類
通過提前抓取將Dog連接獲得,而避免初始化proxy帶來的額外開銷也是可能的。這是通過addJoin()方法進行的,這個方法可以讓你將關聯或集合連接進來。

2

3

上面這個例子中,返回的Cat對象,其dog屬性被完全初始化了,不再需要數據庫的額外操作。注意,我們加了一個別名("cat"),以便指明join的目標屬性路徑。通過同樣的提前連接也可以作用于集合類,例如,假若Cat有一個指向Dog的一對多關聯。

2

3

1.4 返回多個實體
到目前為止,結果集字段名被假定為和映射文件中指定的的字段名是一致的。假若SQL查詢連接了多個表,同一個字段名可能在多個表中出現多次,這就會造成問題。
下面的查詢中需要使用字段別名注射(這個例子本身會失敗):

2

3

這個查詢的本意是希望每行返回兩個Cat實例,一個是cat,另一個是它的媽媽。但是因為它們的字段名被映射為相同的,而且在某些數據庫中,返回的字段別名是“c.ID”,"c.NAME"這樣的形式,而它們和在映射文件中的名字("ID"和"NAME")不匹配,這就會造成失敗。
下面的形式可以解決字段名重復:

2

3

這個查詢指明:SQL查詢語句,其中包含占位符來讓Hibernate注射字段別名,查詢返回的實體
上面使用的{cat.*}和{mother.*}標記是作為“所有屬性”的簡寫形式出現的。當然你也可以明確地羅列出字段名,但在這個例子里面我們讓Hibernate來為每個屬性注射SQL字段別名。字段別名的占位符是屬性名加上表別名的前綴。在下面的例子中,我們從另外一個表(cat_log)中通過映射元數據中的指定獲取Cat和它的媽媽。注意,要是我們愿意,我們甚至可以在where子句中使用屬性別名。

2

3

4

5

6

7

大多數情況下,都需要上面的屬性注射,但在使用更加復雜的映射,比如復合屬性、通過標識符構造繼承樹,以及集合類等等情況下,也有一些特別的別名,來允許Hibernate注射合適的別名。
下表列出了使用別名注射參數的不同可能性。注意:下面結果中的別名只是示例,實用時每個別名需要唯一并且不同的名字。
別名注射(alias injection names)描述 | 語法 | 示例 | |
---|---|---|---|
簡單屬性 | {[aliasname].[propertyname] | A_NAME as {item.name} | |
復合屬性 | {[aliasname].[componentname].[propertyname]} | CURRENCY as {item.amount.currency}, VALUE as {item.amount.value} | |
實體辨別器(Discriminator of an entity) | {[aliasname].class} | DISC as {item.class} | |
實體的所有屬性 | {[aliasname].*} | {item.*} | |
集合鍵(collection key) | {[aliasname].key} | ORGID as {coll.key} | |
集合id | {[aliasname].id} | EMPID as {coll.id} | |
集合元素 | {[aliasname].element} | XID as {coll.element} | |
集合元素的屬性 | {[aliasname].element.[propertyname]} | NAME as {coll.element.name} | |
集合元素的所有屬性 | {[aliasname].element.*} | {coll.element.*} | |
集合的所有屬性 | {[aliasname].*} | {coll.*} |
可以對原生sql 查詢使用ResultTransformer。這會返回不受Hibernate管理的實體。

2

這個查詢指定:SQL查詢字符串,結果轉換器(result transformer)
上面的查詢將會返回CatDTO的列表,它將被實例化并且將NAME和BIRTHDAY的值注射入對應的屬性或者字段。
1.6. 處理繼承原生SQL查詢假若其查詢結果實體是繼承樹中的一部分,它必須包含基類和所有子類的所有屬性。
1.7. 參數
原生查詢支持位置參數和命名參數:

2

3

4

5

可以在映射文檔中定義查詢的名字,然后就可以象調用一個命名的HQL查詢一樣直接調用命名SQL查詢.在這種情況下,不需要調用addEntity()方法.
2 <return alias="person" class="eg.Person"/>
3 SELECT person.NAME AS {person.name},
4 person.AGE AS {person.age},
5 person.SEX AS {person.sex}
6 FROM PERSON person
7 WHERE person.NAME LIKE :namePattern
8 </sql-query>

2

3

4

2 <return alias="person" class="eg.Person"/>
3 <return-join alias="address" property="person.mailingAddress"/>
4 SELECT person.NAME AS {person.name},
5 person.AGE AS {person.age},
6 person.SEX AS {person.sex},
7 adddress.STREET AS {address.street},
8 adddress.CITY AS {address.city},
9 adddress.STATE AS {address.state},
10 adddress.ZIP AS {address.zip}
11 FROM PERSON person
12 JOIN ADDRESS adddress
13 ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
14 WHERE person.NAME LIKE :namePattern
15 </sql-query>

2

3

4

5

6

7

2 <return alias="person" class="eg.Person"/>
3 <return-join alias="address" property="person.mailingAddress"/>
4 </resultset>
5
6 <sql-query name="personsWith" resultset-ref="personAddress">
7 SELECT person.NAME AS {person.name},
8 person.AGE AS {person.age},
9 person.SEX AS {person.sex},
10 adddress.STREET AS {address.street},
11 adddress.CITY AS {address.city},
12 adddress.STATE AS {address.state},
13 adddress.ZIP AS {address.zip}
14 FROM PERSON person
15 JOIN ADDRESS adddress
16 ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
17 WHERE person.NAME LIKE :namePattern
18 </sql-query>
2 "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
3 )
4 .setResultSetMapping("catAndKitten")
5 .list();
使用<return-property>你可以明確的告訴Hibernate使用哪些字段別名,這取代了使用{}-語法 來讓Hibernate注入它自己的別名.

2

3

4

5

6

7

8

9

10

11

2 <return alias="emp" class="Employment">
3 <return-property name="salary">
4 <return-column name="VALUE"/>
5 <return-column name="CURRENCY"/>
6 </return-property>
7 <return-property name="endDate" column="myEndDate"/>
8 </return>
9 SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
10 STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
11 REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
12 FROM EMPLOYMENT
13 WHERE EMPLOYER = :id AND ENDDATE IS NULL
14 ORDER BY STARTDATE ASC
15 </sql-query>
如果你映射一個識別器(discriminator),你必須使用<return-discriminator> 來指定識別器字段
2.2. 使用存儲過程來查詢
Hibernate 3引入了對存儲過程查詢(stored procedure)和函數(function)的支持.以下的說明中,這二者一般都適用。 存儲過程/函數必須返回一個結果集,作為Hibernate能夠使用的第一個外部參數.
2 <return alias="emp" class="Employment">
3 <return-property name="employee" column="EMPLOYEE"/>
4 <return-property name="employer" column="EMPLOYER"/>
5 <return-property name="startDate" column="STARTDATE"/>
6 <return-property name="endDate" column="ENDDATE"/>
7 <return-property name="regionCode" column="REGIONCODE"/>
8 <return-property name="id" column="EID"/>
9 <return-property name="salary">
10 <return-column name="VALUE"/>
11 <return-column name="CURRENCY"/>
12 </return-property>
13 </return>
14 { ? = call selectAllEmployments() }
15 </sql-query>
注意存儲過程當前僅僅返回標量和實體.現在不支持<return-join>和<load-collection>
2.2.1. 使用存儲過程的規則和限制
為了在Hibernate中使用存儲過程,你必須遵循一些規則.不遵循這些規則的存儲過程將不可用.如果你仍然想要使用他們, 你必須通過session.connection()來執行他們.這些規則針對于不同的數據庫.因為數據庫 提供商有各種不同的存儲過程語法和語義.
對存儲過程進行的查詢無法使用setFirstResult()/setMaxResults()進行分頁。
建議采用的調用方式是標準SQL92: { ? = call functionName(<parameters>) } 或者 { ? = call procedureName(<parameters>}.原生調用語法不被支持。