hql语句的语法
一、HQL查询的from子句
from是最简单的语句,也是最基本的HQL语句。from关键字后紧跟持久化类的类名。
例如:
from Person 表明从Person持久化类中选出全部的实例
推荐为Person持久化类的每个实例起别名,例如:
from Person as p
p作为Person的实例的别名,因此也应该遵守Java的命名规则:第一个单词的首字母小写,后面每个单词的首字母大写。
命名别名时,as关键字是可选的,但为了增加可读性,建议保留。
from 后还可同时出现多个持久化类,此时将产生一个笛卡尔积或跨表的连接,但实际上这种用法很少使用,因为通常我们可能需要使用跨表的连接,此时可以考虑使用隐式连接或显示连接,而不是直接在from后紧跟多个表名。
二、关联和连接
Hibernate使用关联映射来处理底层数据表之间的连接,一旦我们提供了正确的关联映射后,当程序通过Hibernate进行持久化访问时,将可利用Hibernate的关联来进行连接。
HQL支持两种关联连接(join)的形式:隐式(implicit)与显示(explicit)。
隐式连接形式不适用join关键字,使用英文点号(.)来隐式连接来关联实体,而Hibernate底层将自动进行关联查询。如下HQL语句:
from Person p where p.myEvent.title > :title
上面的p.myEvent属性的实质是一个持久化实体,因此Hibernate底层隐式地自动进行连接查询。
显示连接则需要使用xxx join关键字,例如如下语句:
//使用显示连接
from Person p
inner join p.myEvent event
where event.happenDate < :endDate
使用显示连接时,可以为相关联的实体,甚至是关联集合中的全部元素指定一个别名。
Hibernate支持的HQL连接类型,可使用如下几种连接方式:
inner join(内连接),可简写成join。
left outer join(左外连接),可简写成left join。
right outer join(右外连接),可简写成right join。
full join(全连接),并不常用。
使用显示连接时,还可通过HQL的with关键字来提供额外的连接条件,例如如下HQL语句:
from Person p
inner join p.myEvent event
with p.id > event.id
where event.happenDate < :endDate
HQL语句中的with关键字的作用基本等同于SQL99中on关键字的作用:都是用于指定连接条件。通过在HQL语句中使用with关键字,可以让HQL语句执行非等值连接查询。
由于表连接的方式都是基于底层SQL来实现的,如果底层不支持这些外连接,那么执行对应的HQL时就会相应地引发异常。
三、隐式连接和显示连接有如下两点区别:
(1)隐式连接底层转换成SQL92的内连接,显示连接层将转换成SQL99的多表连接。
(2)隐式连接和显示连接查询后返回的结果不同。
当HQL语句中省略select关键字时,使用隐式连接查询返回的结果是多个被查询实体组成的集合。
当HQL语句中省略select关键字时,使用显示连接查询返回的结果也是集合,但集合元素是被查询持久化对象、所有被关联的持久化对象所组成的数组。
注意:
对于Hibernate3.2.3以后的版本,如果关联实体是单个实体或单个的组件属性,HQL依然可以似乎用英文点号(.)来隐式连接关联实体或组件;但如果关联实体是集合(包括1-N关联、N-N关联和集合元素时组件等),则必须使用xxx join来显示连接关联实体或组件。
对于集合属性的,Hibernate默认采用延迟加载策略,解决办法:
(2.1)可以在Hibernate映射文件中指定lazy="false"来关闭延迟加载。
(2.2)使用join fetch,通常无须指定别名,因为相关联的对象不应当在where子句(或其他任何子句)中使用。而且被关联的对象也不会再被查询的结果中直接返回,而是应该通过其父对象来访问。
使用fetch关键字时,有如下几个注意点:
fetch不应该与setMaxResults()或setFirstResult()共用。因为这些操作是基于结果集的,而在预先抓取集合类时可能包含重复的数据,即无法预先知道精确的行数。
fetch不能与独立的with条件一起使用。
如果在一次查询中fetch多个集合,可以查询返回笛卡尔积,因此请多加注意。
对bag映射而言,同时join fetch多个集合时可能出现非预期结果,因此需要谨慎使用。
full join fetch 与right join fetch是没有任何意义的。
程序里希望预加载那些原本应延迟加载的属性,则可以通过fetch all properties来强制Hibernate立即抓取这些属性。例如:
from Document fetch all properties order by name
四、HQL查询的select子句
(1)select子句用于选择指定的属性或直接选择某个实体,当然select选择的属性必须是from后持久化类包含的属性。
例如:
select p.name from Person as p
(2)select可以选择任意属性,即不仅可以选择持久化类的直接属性,还可以选择组件属性包含的属性。例如:
select p.name.firstName from Person as p
(3)在特殊情况下,如果select后只有一项(包括持久化实例或属性),则查询得到的集合元素就是该持久化实例或属性。
(4)如果select后有多个项,则每个集合就是选择出的多项组成的数组。
例如:
select p.name,p from Person as p
执行该HQL语句得到的集合元素时类似于[String,Person]结构的数组,其中第一个元素时Person实例的name属性,第二个元素时Person实例。
注意:即使select后的列表项选出某个持久化类的全部属性,这些属性依然是属性,Hibernate不会将这些属性封装成对象。只有在select后的列表里给出持久化类的别名(其实就是实例名),Hibernate才会将该项封装成一个持久化实体。
(5)select支持将选择出的属性存入一个List对象中。
例如:
select new list(p.name, p.address) from Person as p
(6)select支持将选择出的属性封装成对象,前提是该对象拥有支持这些属性的构造器。
例如:
select new ClassTest(p,name, p.address) from Person as p;
而ClassTest必须有如下的构造器:ClassTest(String s1, String s2)
(7)select还支持给选中的表达式命名别名。例如:
select p.name as personName from P