Hibernate查詢語言HQL 八大要點(diǎn)
Hibernate擁有一種功能非常強(qiáng)大的查詢語言,這種語言被有意得與SQL非常相似,便于開發(fā)人員掌握。但不要被HQL的語法表面所迷惑,HQL完全是面向?qū)ο蟮?,可以用來過程多態(tài)、繼承、關(guān)聯(lián)等關(guān)系。
1大小寫敏感(Case Sensitivity)
HQL中的使用的Java的類名和屬性名是大小寫敏感的,其他的關(guān)鍵字都是大小寫不敏感的。所以“SeLeCT”等同與“sELEct”,也等同于“SELECT”,因?yàn)樗皇荍ava類名,也不是Java類的屬性名。但Java類net.sf.hibernate.eg.FOO不等同于net.sf.hibernate.eg.Foo,同樣foo.barSet也不等同于foo.BARSET。
在本手冊(cè)中,HQL中的關(guān)鍵字均采用小寫,一些用戶可能發(fā)現(xiàn)HQL的關(guān)鍵字采用大寫更易讀,但我們也發(fā)現(xiàn),當(dāng)把這些HQL嵌入Java代碼中,看起來很丑陋。
2from從句(The from clause)
Hibernate中最簡(jiǎn)單的from查詢可能是:
- from eg.Cat
只是簡(jiǎn)單的返回eg.Cat類的所有實(shí)例。
在很多時(shí)候你可能需要為類設(shè)置別名(alias),因?yàn)槟憧赡苄枰诓樵兊钠渌糠忠肅at。
- from eg.Cat as cat
關(guān)鍵字as是可選的,我們也可以寫成:
- from eg.Cat cat
可以出現(xiàn)多個(gè)類,然后返回一個(gè)“笛卡兒積”或交叉連接:
- from Formula as form, Parameter as param
HQL中的別名用小寫字母是一個(gè)好習(xí)慣,符合Java本地變量的命名規(guī)范。
3關(guān)聯(lián)和連接(Associations and joins)
我們使用別名關(guān)聯(lián)實(shí)體、甚至用join來關(guān)聯(lián)值的集合的元素。
- from eg.Cat as cat
- inner join cat.mate as mate
- left outer join cat.kittens as kitten
- from eg.Cat as cat left join cat.mate.kittens as kittens
- from Formula form full join form.parameter param
支持的連接類型借鑒自ANSI SQL:
· inner join
· left outer join
· right outer join
· full join (不常用)
inner join, left outer join和right outer join可以簡(jiǎn)寫。
- from eg.Cat as cat
- join cat.mate as mate
- left join cat.kittens as kitten
另外,一個(gè)“fetch”連接允許使用單連接來關(guān)聯(lián)或值的集合,使它們可以和父對(duì)象一起來初始化。這在使用Collection的情況下特別有用。
- from eg.Cat as cat
- inner join fetch cat.mate
- left join fetch cat.kittens
fetch join通常不需要設(shè)置別名,因?yàn)楸魂P(guān)聯(lián)的對(duì)象不應(yīng)該被用在where從句中,也不能用在其他的任何從句中。
被關(guān)聯(lián)的對(duì)象不能直接在查詢結(jié)果中返回,他們可以通過父對(duì)象來訪問。
請(qǐng)注意:在目前的實(shí)現(xiàn)中,在查詢中只能返回一個(gè)集合。另外還要注意,fetch可能不用在被scroll()和iterator()調(diào)用的查詢中。***還要注意,full join fetch和right join fetch是沒有意義的。
4 select從句(The select clause)
select從句用來挑選在結(jié)果集中返回的對(duì)象和屬性:
- select cat.mate from eg.Cat cat
上面這個(gè)查詢返回所有貓的配偶。
你也可以使用elements函數(shù)返回集合的元素。下面的查詢將返回任何貓(Cat)的所有小貓(Kitten)。
- select elements(cat.kittens) from eg.Cat cat
查詢也可以返回任何值類型(包括Component類型的屬性)的屬性:
- select cat.name from eg.DomesticCat cat
- where cat.name like 'fri%'
- select cust.name.firstName from Customer as cust
查詢可以返回多個(gè)對(duì)象,也可以返回作為Object[]類型的數(shù)組的屬性。
- select mother, offspr, mate.name
- from eg.DomesticCat as mother
- inner join mother.mate as mate
- left outer join mother.kittens as offspr
或者作為一個(gè)實(shí)際的Java對(duì)象:
- select new Family(mother, mate, offspr)
- from eg.DomesticCat as mother
- join mother.mate as mate
- left join mother.kittens as offspr
上面的這個(gè)查詢語句假設(shè)Family類有適當(dāng)?shù)臉?gòu)造函數(shù)。
5 聚集函數(shù)(Aggregate functions)
查詢可以使用屬性的聚集函數(shù):
- select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat) from eg.Cat cat
select從句的聚集函數(shù)中可以出現(xiàn)集合:
select cat, count( elements(cat.kittens) ) from eg.Cat cat group by cat
支持的聚集函數(shù)有:
· avg(...), sum(...), min(...), max(...)
· count(*)
· count(...), count(distinct ...), count(all...)
distinct 和all關(guān)鍵字的意義與用法和SQL中相同:
- select distinct cat.name from eg.Cat cat
- select count(distinct cat.name), count(cat) from eg.Cat cat
6 多態(tài)(polymorphism)
一個(gè)查詢:from eg.Cat as cat,它返回的不只是Cat,也有DomesticCat(家貓)這樣的子類。Hibernate可以在from從句中指定任何Java類和接口,查詢將返回繼承自該類和實(shí)現(xiàn)了該接口的所有的持久類的實(shí)例。下面的查詢將返回所有持久的對(duì)象:
- from java.lang.Object o
指定的接口可以被多個(gè)不同的持久類實(shí)現(xiàn):
- from eg.Named n, eg.Named m where n.name = m.name
注意***2個(gè)查詢將需要超過1個(gè)SQL的select,這意味著不能夠按照從句指定的排列次序排列整個(gè)結(jié)果集。這也意味著你不能用Query.scroll()來調(diào)用這些查詢。
7 where從句(The where clause)
where從句是你可以按照自己指定的條件更精確的返回實(shí)例:
- from eg.Cat as cat where cat.name='Fritz'
復(fù)合表達(dá)式使where從句功能非常強(qiáng)大:
- from eg.Cat as cat where cat.name='Fritz'
這個(gè)查詢將被翻譯成帶有一個(gè)連接的SQL查詢語句。
如果你寫下這句查詢:
- from eg.Foo foo where foo.bar.baz.customer.address.city is not null
這個(gè)查詢翻譯成SQL語句需要4個(gè)表連接。
“=”操作符不僅可以比較屬性,也可以比較實(shí)例:
- from eg.Cat cat, eg.Cat rival where cat.mate = rival.mate
- select cat, mate from eg.Cat cat, eg.Cat mate where cat.mate = mate
一個(gè)叫id的特殊的屬性被用來引用一個(gè)對(duì)象的唯一標(biāo)識(shí)符,你也可以用對(duì)象的屬性名。
- from eg.Cat as cat where cat.id = 123
- from eg.Cat as cat where cat.mate.id = 69
這個(gè)查詢要比上一個(gè)有效率,因?yàn)椴恍枰磉B接。
可以使用復(fù)合主鍵的屬性。假設(shè)person有一個(gè)由medicareNumber和country構(gòu)成的符合主鍵:
- from bank.Person person
- where person.id.country = 'AU'
- and person.id.medicareNumber = 123456
- from bank.Account account
- where account.owner.id.country = 'AU'
- and account.owner.id.medicareNumber = 123456
再重復(fù)一次,第二個(gè)查詢效率高些。
同樣,一個(gè)指定了屬性的類在多態(tài)持久(polymorphic persistence)的情況下訪問實(shí)體的discriminator value。
一個(gè)被嵌入到where從句中的Java類名將被翻譯成它的discriminator value。
from eg.Cat cat where cat.class = eg.DomesticCat
你也可以指定組件(component)的屬性和用戶自己定義的合成類型(及組件的組件等等)。
永遠(yuǎn)也不要使用一個(gè)以組件的屬性結(jié)尾的路徑表達(dá)式。舉個(gè)例子,假設(shè)store.owner是一個(gè)帶有一個(gè)叫address組件的實(shí)體:
- store.owner.address.city //正確
- store.owner.address //錯(cuò)誤!
一個(gè)叫“any”的類型有2個(gè)特別的屬性,一個(gè)是id,另一個(gè)是class,它允許我們用下面的辦法進(jìn)行連接(join)。AuditLog.item是一個(gè)用< any>映射的屬性:
- from eg.AuditLog log, eg.Payment payment
- where log.item.class = 'eg.Payment' and log.item.id = payment.id
需要注意的是:查詢中的log.item.class和payment.class將參考完全不同的數(shù)據(jù)庫(kù)列。
8 表達(dá)式(Expressions)
where從句中的表達(dá)式允許你使用SQL中的很多東西:
· 數(shù)學(xué)運(yùn)算符: +, -, *, /
· 二元比較運(yùn)算符: =, >=, < =, < >, !=, like
· 邏輯操作符: and, or, not
· 字符串連接符: ||
· SQL函數(shù),如: upper() and lower()
· 圓括號(hào): ( )
· in, between, is null
· JDBC輸入?yún)?shù): ?
· 指定的參數(shù)::name, :start_date, :x1
· in和between:
- from eg.DomesticCat cat where cat.name between 'A' and 'B'
- from eg.DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )
和否定形式的(negated forms):
- from eg.DomesticCat cat where cat.name not between 'A' and 'B'
- from eg.DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )
· is null和is not null
· 也可以使用特殊的屬性size或size()函數(shù)來測(cè)試集合的大?。?/P>
- from eg.Cat cat where cat.kittens.size > 0
- from eg.Cat cat where size(cat.kittens) > 0
· 對(duì)于有索引的集合,你可以使用特殊屬性minIndex和maxIndex來引用最小索引和***索引。同樣,你也可以使用minElement和maxElement來引用基本類型的集合的minimum和maximum元素。
- from Calendar cal where cal.holidays.maxElement > current date
也可以是函數(shù)的形式:
- from Order order where maxindex(order.items) > 100
- from Order order where minelement(order.items) > 10000
在傳遞索引和元素給集合時(shí)(elements and indices函數(shù))和傳遞子查詢的結(jié)果集時(shí),SQL函數(shù)any, some, all, exists, in都是被支持的:
- select mother from eg.Cat as mother, eg.Cat as kit
- where kit in elements(foo.kittens)
- select p from eg.NameList list, eg.Person p
- where p.name = some elements(list.names)
- from eg.Cat cat where exists elements(cat.kittens)
- from eg.Player p where 3 > all elements(p.scores)
- from eg.Show show where 'fizard' in indices(show.acts)
請(qǐng)注意:size, elements, indices, minIndex, maxIndex, minElement, maxElement在使用時(shí)有一些限制:
v where從句中的in只用于數(shù)據(jù)庫(kù)的子查詢。
v select從句中的in只用于elements 和indices函數(shù)。
v 帶有索引的元素的collection(arrays, lists, maps)只能在where從句中通過索引引用:
- from Order order where order.items[0].id = 1234
- select person from Person person, Calendar calendar
- where calendar.holidays['national day'] = person.birthDay
- and person.nationality.calendar = calendar
- select item from Item item, Order order
- where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11
- select item from Item item, Order order
- where order.items[ maxindex(order.items) ] = item and order.id = 11
表達(dá)式中的[]的內(nèi)部可以是一個(gè)算術(shù)表達(dá)式:
- select item from Item item, Order order
- where order.items[ size(order.items) - 1 ] = item
HQL為one-to-many關(guān)聯(lián)和值的集合提供了內(nèi)置的index()函數(shù):
- select item, index(item) from Order order
- join order.items item
- where index(item) < 5
被一些特定數(shù)據(jù)庫(kù)支持的SQL函數(shù)可以被使用:
- from eg.DomesticCat cat where upper(cat.name) like 'FRI%'
如果你還不相信上面的一切,那么想想更長(zhǎng)的和更短的可讀的查詢吧:
- select cust
- from Product prod,
- Store store
- inner join store.customers cust
- where prod.name = 'widget'
- and store.location.name in ( 'Melbourne', 'Sydney' )
- and prod = all elements(cust.currentOrder.lineItems)
提示:something like
- SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
- FROM customers cust,
- stores store,
- locations loc,
- store_customers sc,
- product prod
- WHERE prod.name = 'widget'
- AND store.loc_id = loc.id
- AND loc.name IN ( 'Melbourne', 'Sydney' )
- AND sc.store_id = store.id
- AND sc.cust_id = cust.id
- AND prod.id = ALL(
- SELECT item.prod_id
- FROM line_items item, orders o
- WHERE item.order_id = o.id
- AND cust.current_order = o.id)
【編輯推薦】