HQL: Hibernate查询语言
Hibernate配备了一U非常强大的查询语言Q这U语a看上d像SQL。但是不要被语法l构上的怼所qhQHQL是非常有意识的被设计为完全面向对象的查询Q它可以理解如ѝ多?和关联之cȝ概念?/span>
除了JavacM属性的名称外,查询语句对大写q不敏感?所?SeLeCT ?sELEct 以及 SELECT 是相同的Q但?org.hibernate.eg.FOO q不{h?org.hibernate.eg.Foo q且 foo.barSet 也不{h?foo.BARSET ?/span>
本手册中的HQL关键字将使用写字母. 很多用户发现使用完全大写的关键字会查询语句 的可L更? 但我们发玎ͼ当把查询语句嵌入到Java语句中的时候用大写关键字比较隄?/span>
Hibernate中最单的查询语句的Ş式如下:
from eg.Cat
该子句简单的q回eg.Cat cȝ所有实例。通常我们不需要用类的全限定? 因ؓ auto-import Q自动引入) 是缺省的情况。所以我们几乎只使用如下的简单写法:
from Cat
大多数情况下, 你需要指定一?span>别名 , 原因是你可能需?在查询语句的其它部分引用?tt>Cat
from Cat as cat
q个语句把别?tt>cat 指定l类Cat 的实? q样我们可以在随后的查询中使用此别名了。关键字as 是可选的Q我们也可以q样?
from Cat cat
子句中可以同时出现多个类, 其查询结果是产生一个笛卡儿U或产生跨表的连接?/span>
from Formula, Parameter
from Formula as form, Parameter as param
查询语句中别名的开头部分小写被认ؓ是实践中的好习惯Q?q样做与Java变量的命名标准保持了一?(比如Q?tt>domesticCat )?/span>
我们也可以ؓ相关联的实体甚至是对一个集合中的全部元素指定一个别? q时要用关键字join ?/span>
from Cat as cat
inner join cat.mate as mate
left outer join cat.kittens as kitten
from Cat as cat left join cat.mate.kittens as kittens
from Formula form full join form.parameter param
受支持的q接cd是从ANSI SQL中借鉴来的?/span>
inner join Q内q接Q?/span>
left outer join Q左外连接)
right outer join Q右外连接)
full join (全连接,q不常用)
语句inner join , left outer join 以及 right outer join 可以写?/span>
from Cat as cat
join cat.mate as mate
left join cat.kittens as kitten
q有Q一?fetch"q接允许仅仅使用一个选择语句将相关联的对象或一l值的集合随着他们的父对象的初始化而被初始化,q种Ҏ在用到集合的情况下其有用Q对于关联和集合来说Q它有效的代替了映射文g中的外联接与延迟声明Qlazy declarationsQ? 查看 W?0.1?“ 抓取{略(Fetching strategies) ” 以获得等多的信息?/span>
from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens
一个fetchq接通常不需要被指定别名, 因ؓ相关联的对象不应当被用在 where 子句 (或其它Q何子?中。同Ӟ相关联的对象q不在查询的l果中直接返回,但可以通过他们的父对象来访问到他们?/span>
注意fetch 构造变量在使用?tt>scroll() ?iterate() 函数的查询中是不能用的。最后注意,使用full join fetch ?right join fetch 是没有意义的?/span>
如果你用属性别的延迟获取Qlazy fetchingQ(q是通过重新~写字节码实现的Q,可以使用 fetch all properties 来强制Hibernate立即取得那些原本需要gq加载的属性(在第一个查询中Q?/span>
from Document fetch all properties order by name
from Document doc fetch all properties where lower(doc.name) like '%cats%'
select 子句选择哪些对象与属性返回到查询l果集中. 考虑如下情况:
select mate
from Cat as cat
inner join cat.mate as mate
该语句将选择mate s of other Cat s。(其他猫的配偶Q?实际? 你可以更z的用以下的查询语句表达相同的含?
select cat.mate from Cat cat
查询语句可以q回gؓMcd的属性,包括q回cd为某U组?Component)的属?
select cat.name from DomesticCat cat
where cat.name like 'fri%'
select cust.name.firstName from Customer as cust
查询语句可以q回多个对象和(或)属性,存放?Object[] 队列?
select mother, offspr, mate.name
from DomesticCat as mother
inner join mother.mate as mate
left outer join mother.kittens as offspr
或存攑֜一?tt>List 对象?
select new list(mother, offspr, mate.name)
from DomesticCat as mother
inner join mother.mate as mate
left outer join mother.kittens as offspr
也可能直接返回一个实际的cd安全的Java对象,
select new Family(mother, mate, offspr)
from DomesticCat as mother
join mother.mate as mate
left join mother.kittens as offspr
假设c?tt>Family 有一个合适的构造函?
你可以用关键字as l?#8220;被选择了的表达?#8221;指派别名:
select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
from Cat cat
q种做法在与子句select new map 一起用时最有用:
select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
from Cat cat
该查询返回了一?tt>Map 的对象,内容是别名与被选择的值组成的?值映?/span>
HQL查询甚至可以q回作用于属性之上的聚集函数的计结?
select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
from Cat cat
受支持的聚集函数如下Q?/span>
avg(...), sum(...), min(...), max(...)
count(*)
count(...), count(distinct ...), count(all...)
你可以在选择子句中用数学操作符、连接以及经q验证的SQL函数Q?/span>
select cat.weight + sum(kitten.weight)
from Cat cat
join cat.kittens kitten
group by cat.id, cat.weight
select firstName||' '||initial||' '||upper(lastName) from Person
关键?tt>distinct ?tt>all 也可以用,它们h与SQL相同的语?
select distinct cat.name from Cat cat
select count(distinct cat.name), count(cat) from Cat cat
一个如下的查询语句:
from Cat as cat
不仅q回Cat cȝ实例, 也同时返回子c?DomesticCat 的实? Hibernate 可以?tt>from 子句中指?span>M Java cL接口. 查询会返回承了该类的所有持久化子类的实例或q回声明了该接口的所有持久化cȝ实例。下面的查询语句q回所有的被持久化的对象:
from java.lang.Object o
接口Named 可能被各U各L持久化类声明Q?/span>
from Named n, Named m where n.name = m.name
注意Q最后的两个查询需要超q一个的SQL SELECT .q表?tt>order by 子句 没有Ҏ个结果集q行正确的排? (q也说明你不能对q样的查询?tt>Query.scroll() Ҏ.)
where 子句允许你将q回的实例列表的范围~小. 如果没有指定别名Q你可以使用属性名来直接引用属?
from Cat where name='Fritz'
如果指派了别名,需要用完整的属性名:
from Cat as cat where cat.name='Fritz'
q回名ؓQ属性name{于Q?Fritz'?tt>Cat cȝ实例?/span>
select foo
from Foo foo, Bar bar
where foo.startDate = bar.date
返回所有满下面条件的Foo cȝ实例Q存在如下的bar 的一个实例,?tt>date 属性等?Foo ?tt>startDate 属性?复合路径表达式?tt>where 子句非常的强大,考虑如下情况Q?/span>
from Cat cat where cat.mate.name is not null
该查询将被翻译成Z个含有表q接Q内q接Q的SQL查询。如果你打算写像q样的查询语?/span>
from Foo foo
where foo.bar.baz.customer.address.city is not null
在SQL中,你ؓ达此目的需要进行一个四表连接的查询?/span>
= q算W不仅可以被用来比较属性的|也可以用来比较实例:
from Cat cat, Cat rival where cat.mate = rival.mate
select cat, mate
from Cat cat, Cat mate
where cat.mate = mate
Ҏ属性(写Q?tt>id 可以用来表示一个对象的唯一的标识符。(你也可以使用该对象的属性名。)
from Cat as cat where cat.id = 123
from Cat as cat where cat.mate.id = 69
W二个查询是有效的。此时不需要进行表q接Q?/span>
同样也可以用复合标识符。比?tt>Person cL一个复合标识符Q它?tt>country 属??tt>medicareNumber 属性组成?/span>
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
W二个查询也不需要进行表q接?/span>
同样的,Ҏ属?tt>class 在进行多态持久化的情况下被用来存取一个实例的鉴别|discriminator valueQ?一个嵌入到where子句中的Javacȝ名字被转换cȝ鉴别倹{?/span>
from Cat cat where cat.class = DomesticCat
你也可以声明一个属性的cd是组件或者复合用L型(以及q件构成的lg{等Q。永q不要尝试用以lgcd来结路径表达式(path-expression_rQ(与此相反Q你应当使用lg的一个属性来l尾Q?举例来说Q如?tt>store.owner 含有一个包含了lg的实?tt>address
store.owner.address.city // 正确
store.owner.address // 错误!
一?#8220;L”cd有两个特D的属?tt>id ?tt>class , 来允许我们按照下面的方式表达一个连接(AuditLog.item 是一个属性,该属性被映射?tt><any> Q?/span>
from AuditLog log, Payment payment
where log.item.class = 'Payment' and log.item.id = payment.id
注意Q在上面的查询与句中Q?tt>log.item.class ?payment.class 涉及到完全不同的数据库中的列?/span>
?tt>where 子句中允怋用的表达式包括大多数你可以在SQL使用的表辑ּU类:
数学q算W?tt>+, -, *, /
二进制比较运符=, >=, <=, <>, !=, like
逻辑q算W?tt>and, or, not
in , not in , between , is null , is not null , is empty , is not empty , member of 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-QL 3.0定义的Q何函数或操作Q?tt>substring(), trim(), lower(), upper(), length(), locate(), abs(), sqrt(), bit_length()
coalesce() ?nullif()
cast(... as ...) , 其第二个参数是某Hibernatecd的名字,以及extract(... from ...) Q只要ANSI cast() ?extract() 被底层数据库支持
M数据库支持的SQL标量函数Q比?tt>sign() , trunc() , rtrim() , sin()
JDBC参数传入 ?
命名参数:name , :start_date , :x1
SQL 直接帔R 'foo' , 69 , '1970-01-01 10:00:01.0'
Java public static final cd的常?eg.Color.TABBY
关键?tt>in ?tt>between 可按如下Ҏ使用:
from DomesticCat cat where cat.name between 'A' and 'B'
from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )
而且否定的格式也可以如下书写Q?/span>
from DomesticCat cat where cat.name not between 'A' and 'B'
from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )
同样, 子句is null ?tt>is not null 可以被用来测试空?null).
在Hibernate配置文g中声明HQL“查询替代Qquery substitutionsQ?#8221;之后Q布表辑ּQBooleansQ可以在其他表达式中L的?
<property name="hibernate.query.substitutions">true 1, false 0</property>
pȝ该HQL转换为SQL语句Ӟ该设|表明将用字W?1 ?0 ?取代关键?tt>true ?false :
from Cat cat where cat.alive = true
你可以用Ҏ属?tt>size , 或是Ҏ函数size() 试一个集合的大小?/span>
from Cat cat where cat.kittens.size > 0
from Cat cat where size(cat.kittens) > 0
对于索引了(有序Q的集合Q你可以使用minindex ?maxindex 函数来引用到最与最大的索引序数。同理,你可以?tt>minelement ?maxelement 函数来引用到一个基本数据类型的集合中最与最大的元素?/span>
from Calendar cal where maxelement(cal.holidays) > current date
from Order order where maxindex(order.items) > 100
from Order order where minelement(order.items) > 10000
在传递一个集合的索引集或者是元素?elements ?tt>indices 函数) 或者传递一个子查询的结果的时候,可以使用SQL函数any, some, all, exists, in
select mother from Cat as mother, Cat as kit
where kit in elements(foo.kittens)
select p from NameList list, Person p
where p.name = some elements(list.names)
from Cat cat where exists elements(cat.kittens)
from Player p where 3 > all elements(p.scores)
from Show show where 'fizard' in indices(show.acts)
注意Q在Hibernate3U,q些l构变量- size , elements , indices , minindex , maxindex , minelement , maxelement - 只能在where子句中用?/span>
一个被索引q的Q有序的Q集合的元素(arrays, lists, maps)可以在其他烦引中被引用(只能在where子句中)Q?/span>
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
?tt>[] 中的表达式甚臛_以是一个算数表辑ּ?/span>
select item from Item item, Order order
where order.items[ size(order.items) - 1 ] = item
对于一个一对多的关联(one-to-many associationQ或是值的集合中的元素Q?HQL也提供内建的index() 函数Q?/span>
select item, index(item) from Order order
join order.items item
where index(item) < 5
如果底层数据库支持标量的SQL函数Q它们也可以被?/span>
from DomesticCat cat where upper(cat.name) like 'FRI%'
如果你还不能Ҏ有的q些׃不疑Q想想下面的查询。如果用SQLQ语句长度会增长多少Q可L会下降多少Q?/span>
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)
提示: 会像如下的语?/span>
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
)
查询q回的列?list)可以按照一个返回的cLlgQcomponents)中的M属性(propertyQ进行排序:
from DomesticCat cat
order by cat.name asc, cat.weight desc, cat.birthdate
可选的asc ?tt>desc 关键字指明了按照升序或降序进行排?
一个返回聚集?aggregate values)的查询可以按照一个返回的cLlgQcomponents)中的M属性(propertyQ进行分l:
select cat.color, sum(cat.weight), count(cat)
from Cat cat
group by cat.color
select foo.id, avg(name), max(name)
from Foo foo join foo.names name
group by foo.id
having 子句在这里也允许使用.
select cat.color, sum(cat.weight), count(cat)
from Cat cat
group by cat.color
having cat.color in (eg.Color.TABBY, eg.Color.BLACK)
如果底层的数据库支持的话(例如不能在MySQL中?QSQL的一般函C聚集函数也可以出??tt>having ?tt>order by 子句中?/span>
select cat
from Cat cat
join cat.kittens kitten
group by cat
having avg(kitten.weight) > 100
order by count(kitten) asc, sum(kitten.weight) desc
注意group by 子句?order by 子句中都不能包含术表达式(arithmetic expression_rsQ?