天天看點

第十一章 Hibernate的查詢 HQL面向對象的查詢語言

HQL基本上與sql語句在文法上相仿,隻是HQL具有面向對象的特性而已。(本文部分内容是從網絡中擷取而來)

         除了Java類與屬性的名稱外,查詢語句對大小寫并不敏感。是以SeLeCT與sELEct以及SELECT

是相同的,但是org.hibernate.eg.FOO并不等價于org.hibernate.eg.Foo并且foo.barSet也不等價于foo.BARSET。

        本文中的HQL關鍵字将使用小寫字母.很多使用者發現使用完全大寫的關鍵字會使查詢語句的可讀性更強,但我們發現,當把查詢語句嵌入到Java語句中的時候使用大寫關鍵字比較難看。

Hibernate中最簡單的查詢語句的形式如下:

該子句簡單的傳回cn.framelife.hql.Cat類的所有執行個體。通常我們不需要使用類的全限定名,因為auto-import(自動引入)是預設的情況。

是以我們幾乎隻使用如下的簡單寫法:

大多數情況下,你需要指定一個别名,原因是你可能需要 在查詢語句的其它部分引用到Cat

          這個語句把别名cat指定給類Cat的執行個體,這樣我們就可以在随後的查詢中使用此别名了。關鍵字as是可選的,我們也可以這樣寫:

子句中可以同時出現多個類,其查詢結果是産生一個笛卡兒積或産生跨表的連接配接。

查詢語句中别名的開頭部分小寫被認為是實踐中的好習慣,這樣做與Java變量的命名标準保持了一緻(比如,domesticCat)。

我們也可以為相關聯的實體甚至是對一個集合中的全部元素指定一個别名,這時要使用關鍵字join。

受支援的連接配接類型是從ANSISQL中借鑒來的。

innerjoin(内連接配接)

leftouter join(左外連接配接)

rightouter join(右外連接配接)

fulljoin (全連接配接,并不常用)

語句innerjoin, left outer join以及rightouter join可以簡寫。

還有,一個"fetch"連接配接允許僅僅使用一個選擇語句就将相關聯的對象或一組值的集合随着他們的父對象的初始化而被初始化,這種方法在使用到集合的情況下尤其有用,對于關聯和集合來說,它有效的代替了映射檔案中的外聯接與延遲聲明(lazydeclarations).檢視第20.1節

“抓取政策(Fetching strategies)”以獲得等多的資訊。

一個fetch連接配接通常不需要被指定别名,因為相關聯的對象不應當被用在where子句(或其它任何子句)中。同時,相關聯的對象并不在查詢的結果中直接傳回,但可以通過他們的父對象來通路到他們。

注意fetch構造變量在使用了scroll()或iterate()函數的查詢中是不能使用的。最後注意,使用fulljoin

fetch與 right joinfetch是沒有意義的。

如果你使用屬性級别的延遲擷取(lazyfetching)(這是通過重新編寫位元組碼實作的),可以使用fetch all properties來強制Hibernate立即取得那些原本需要延遲加載的屬性(在第一個查詢中)。

select子句選擇将哪些對象與屬性返 回到查詢結果集中.考慮如下情況:

該語句将選擇matesof other Cats。(其他貓的配偶) 實際上,你可以更簡潔的用以下的查詢語句表達相同的含義:

查詢語句可以傳回值為任何類型的屬性,包括傳回類型為某種元件(Component)的屬性:

查詢語句可以傳回多個對象和(或)屬性,存放在Object[]隊列中,

或存放在一個List對象中,

也可能直接傳回一個實際的類型安全的Java對象,

假設類Family有一個合适的構造函數.你可以使用關鍵字as給“被選擇了的表達式”指派别名:

這種做法在與子句select new map一起使用時最有用:

該查詢傳回了一個Map的對象,内容是别名與被選擇的值組成的名-值映射。

HQL查詢甚至可以傳回作用于屬性之上的聚集函數的計算結果:

受支援的聚集函數如下:

你可以在選擇子句中使用數學操作符、連接配接以及經過驗證的SQL函數:

關鍵字distinct與all也可以使用,它們具有與SQL相同的語義.

一個如下的查詢語句:

不僅傳回Cat類的執行個體,也同時傳回子類DomesticCat的執行個體.Hibernate可以在from子句中指定任何Java類或接口.查詢會傳回繼承了該類的所有持久化子類的執行個體或傳回聲明了該接口的所有持久化類的執行個體。下面的查詢語句傳回所有的被持久化的對象:

接口Named可能被各種各樣的持久化類聲明:

注意,最後的兩個查詢将需要超過一個的SQLSELECT.這表明order by子句沒有對整個結果集進行正确的排序.(這也說明你不能對這樣的查詢使用Query.scroll()方法.)

where子句允許你将傳回的執行個體清單的範圍縮小.如果沒有指定别名,你可以使用屬性名來直接引用屬性:

如果指派了别名,需要使用完整的屬性名:

傳回名為(屬性name等于)'Fritz'的Cat類的執行個體。

将傳回所有滿足下面條件的Foo類的執行個體:存在如下的bar的一個執行個體,其date屬性等于Foo的startDate屬性。複合路徑表達式使得where子句非常的強大,考慮如下情況:

該查詢将被翻譯成為一個含有表連接配接(内連接配接)的SQL查詢。如果你打算寫像這樣的查詢語句

在SQL中,你為達此目的将需要進行一個四表連接配接的查詢。

=運算符不僅可以被用來比較屬性的值,也可以用來比較執行個體:

特殊屬性(小寫)id可以用來表示一個對象的唯一的辨別符。(你也可以使用該對象的屬性名。)

第二個查詢是有效的。此時不需要進行表連接配接!

同樣也可以使用複合辨別符。比如Person類有一個複合辨別符,它由country屬性與medicareNumber屬性組成。

第二個查詢也不需要進行表連接配接。

同樣的,特殊屬性class在進行多态持久化的情況下被用來存取一個執行個體的鑒别值(discriminatorvalue)。 一個嵌入到where子句中的Java類的名字将被轉換為該類的鑒别值。

你也可以聲明一個屬性的類型是元件或者複合使用者類型(以及由元件構成的元件等等)。永遠不要嘗試使用以元件類型來結尾的路徑表達式(path-expression)(與此相反,你應當使用元件的一個屬性來結尾)。舉例來說,如果store.owner含有一個包含了元件的實體address

一個“任意”類型有兩個特殊的屬性id和class,來允許我們按照下面的方式表達一個連接配接(AuditLog.item是一個屬性,該屬性被映射為<any>)。

注意,在上面的查詢與句中,log.item.class和payment.class将涉及到完全不同的資料庫中的列。

在where子句中允許使用的表達式包括大多數你可以在SQL使用的表達式種類:

數學運算符+,-, *, /

二進制比較運算符=,>=, <=, <>, !=, like

邏輯運算符and,or, not

in,not in, between, is null, is not null, is empty, is not empty, memberof and not member of

"簡單的"case, case ... when ... then ... else ... end,和"搜尋"case,

case when ... then ... else ... end

字元串連接配接符...||...or concat(...,...)

current_date(),current_time(), current_timestamp()

second(...),minute(...), hour(...), day(...), month(...), year(...),

EJB-QL3.0定義的任何函數或操作:substring(),trim(), lower(), upper(), length(), locate(), abs(), sqrt(),bit_length()

coalesce()和nullif()

cast(...as ...),其第二個參數是某Hibernate類型的名字,以及extract(...from

...),隻要ANSIcast()和extract()被底層資料庫支援

任何資料庫支援的SQL标量函數,比如sign(),trunc(), rtrim(), sin()

JDBC參數傳入?

命名參數:name,:start_date, :x1

SQL直接常量'foo', 69,'1970-01-01 10:00:01.0'

Javapublic static final類型的常量eg.Color.TABBY

關鍵字in與between可按如下方法使用:

而且否定的格式也可以如下書寫:

同樣,子句is null與isnot null可以被用來測試空值(null).

在Hibernate配置檔案中聲明HQL“查詢替代(querysubstitutions)”之後,

布爾表達式(Booleans)可以在其他表達式中輕松的使用:

系統将該HQL轉換為SQL語句時,該設定表明将用字元1和0來

取代關鍵字true和false:

你可以用特殊屬性size,或是特殊函數size()測試一個集合的大小。

對于索引了(有序)的集合,你可以使用minindex與maxindex函數來引用到最小與最大的索引序數。同理,你可以使用minelement與maxelement函數來引用到一個基本資料類型的集合中最小與最大的元素。

在傳遞一個集合的索引集或者是元素集(elements與indices函數)或者傳遞一個子查詢的結果的時候,可以使用SQL函數any,some,

all, exists, in

注意,在Hibernate3種,這些結構變量-size, elements, indices, minindex, maxindex, minelement, maxelement -隻能在where子句中使用。

一個被索引過的(有序的)集合的元素(arrays,lists, maps)可以在其他索引中被引用(隻能在where子句中):

在[]中的表達式甚至可以是一個算數表達式。

對于一個一對多的關聯(one-to-manyassociation)或是值的集合中的元素,HQL也提供内建的index()函數,

如果底層資料庫支援标量的SQL函數,它們也可以被使用

如果你還不能對所有的這些深信不疑,想想下面的查詢。如果使用SQL,語句長度會增長多少,可讀性會下降多少:

提示:會像如下的語句

查詢傳回的清單(list)可以按照一個傳回的類或元件(components)中的任何屬性(property)進行排序:

可選的asc或desc關鍵字指明了按照升序或降序進行排序.

一個傳回聚集值(aggregatevalues)的查詢可以按照一個傳回的類或元件(components)中的任何屬性(property)進行分組:

having子句在這裡也允許使用.

如果底層的資料庫支援的話(例如不能在MySQL中使用),SQL的一般函數與聚集函數也可以出現在having與orderby子句中。

注意groupby子句與 orderby子句中都不能包含算術表達式(arithmeticexpressions)

.

對于支援子查詢的資料庫,Hibernate支援在查詢中使用子查詢。一個子查詢必須被圓括号包圍起來(經常是SQL聚集函數的圓括号)。甚至互相關聯的子查詢(引用到外部查詢中的别名的子查詢)也是允許的。

在select清單中包含一個表達式以上的子查詢,你可以使用一個元組構造符(tupleconstructors):

注意在某些資料庫中(不包括Oracle與HSQL),你也可以在其他語境中使用元組構造符,比如查詢使用者類型的元件與組合:

該查詢等價于更複雜的:

有兩個很好的理由使你不應當作這樣的事情:首先,它不完全适用于各個資料庫平台;其次,查詢現在依賴于映射檔案中屬性的順序。