- 译者序
- 前言
- 本书怎么使用
- 本书排版字体约定
- 本书网站
- 致谢
- 第一部分 Hibernate 快速入门
- 第 1 章 安装和设置
- 第 2 章 映射简介
- 第 3 章 驾驭 Hibernate
- 第 4 章 集合与关联
- 第 5 章 更复杂的关联
- 第 6 章 自定义值类型
- 第 7 章 映射标注
- 第 8 章 条件查询
- 第 9 章 浅谈 HQL
- 第二部分 与其他工具的集成
- 第 10 章 将 Hibernate 连接到 MySQL
- 第 11 章 Hibernate 与 Eclipse:Hibernate Tools 使用实战
- 第 12 章 Maven 进阶
- 第 13 章 Spring 入门:Hibernate 与 Spring
- 第 14 章 画龙点睛:用 Stripes 集成 Spring 和 Hibernate
- 附录 A Hibernate 类型
- 附录 B Criteria API
- 附录 C Hibernate SQL 方言
- 附录 D Spring 事务支持
- 附录 E 参考资源
- 作者简介
- 封面介绍
使用聚合值
我们时常需要从数据库中提取摘要信息,尤其是在做报表的时候:有多少?平均值?最长的?HQL 也支持这一功能,办法就是提供与 SQL 类似的聚合函数(aggregate function)。当然,在 HQL 中,这些函数是针对持久化类的属性而进行运算的。
应该怎么做
我们以目前现有的一些查询测试框架为基础试一试吧。首先,在 Track.hbm.xml 中现有的查询内容之后再新添加例 9-15 所示的查询内容。
例 9-15:一个用于收集曲目的聚合信息的查询
<query name="com.oreilly.hh.trackSummary">
<![CDATA[
select count(*),min(track.playTime),max(track.playTime)
from Track as track
]]>
</query>
我原来试图取出平均播放时间,但很不幸,HSQLDB 不知道应该如何为非数值的字段计算平均值,因为这个属性是保存在数据库类型为 date(日期)的字段中。
接下来,我们必须写一个方法去执行这个查询,并显示结果。把例 9-16 所示的代码加进 QueryTest.java,就放在 tracksNoLongerThan()方法的后面。
例 9-16:执行 trackSummary 查询的方法
/**
*Print summary information about all tracks.
*
*@param session the Hibernate session that can retrieve data.
**/
public static void printTrackSummary(Session session){
Query query=session.getNamedQuery("com.oreilly.hh.trackSummary");
Object[]results=(Object[])query.uniqueResult();
System.out.println("Summary information:");
System.out.println("Total tracks:"+results[0]);
System.out.println("Shortest track:"+results[1]);
System.out.println("Longest track:"+results[2]);
}
由于我们只在查询中使用聚合函数,因此我们知道返回的结果只会有一行数据。在这种情况下,就可以使用 Query 接口提供的另一个更加方便的 uniqueResult()方法,这样能免去取回一个列表,并把列表的第一个元素取出来的麻烦。如本节前面的 9.2 节所述,因为我们要求的是几个不同的值,因此结果将会是一个 Object 数组,其元素就是我们请求的那些值,它们的顺序与查询结果中的排列顺序相同。(这段代码看起来有些难看,使用了晦涩难懂的数字式数组引用。这就是我们演示的为什么需要为查询创建“报表对象”的原因了,使用报表对象将会让处理变得比现在要方便得多。在普通的 SQL 语句中,你可以为字段起个名称,通过名称从 ResultSet(结果集)中取回字段值;在 HQL 中,你可以声明类,并在查询中创建这个类的实例。)
我们还需要在 main()中新添加一行代码来调用这个方法。可以将这行代码放在打印输出选择的曲目详细信息的循环之后,如例 9-17 所示。
例 9-17:在 QueryTest.java 中的 main()中新增加一行,以显示新的摘要信息
……
System.out.println("Track:"+aTitle+"[ID="+anID+']');
}printTrackSummary(session);
}finally{
//No matter what, close the session
……
增加好代码以后,执行 ant qtest,就可以得到新的输出,如例 9-18 所示。
例 9-18:摘要输出
……
qtest:
[java]Track:Video Killed the Radio Star[ID=2]
[java]Track:Test Tone 1[ID=7]
[java]Track:Russian Trance[ID=1]
[java]Track:Never Turn Your Back on Mother Earth[ID=12]
[java]Track:Motherless Child[ID=13]
[java]Track:In a Manner of Speaking[ID=9]
[java]Track:Gone[ID=11]
[java]Summary information:
[java]Total tracks:13
[java]Shortest track:00:00:10
[java]Longest track:00:07:39
BUILD SUCCESSFUL
Total time:9 seconds
相当简单吧。我们再试试比较难处理的—从连接表中获取信息。曲目有一个关联到艺人的集合。假设我们想取出和特定艺人相关联的曲目的摘要信息,而不是所有曲目的摘要信息。例 9-19 演示了查询语句中新增加的部分。
例 9-19:获取特定艺人相关的曲目摘要信息
<query name="com.oreilly.hh.trackSummary">
<![CDATA[
select count(*),min(track.playTime),max(track.playTime)
from Track as track
where:artist in elements(track.artists)
]]>
</query>
为了过滤想看到的曲目,我们新增了一个 where 子句,以及一个命名参数 artist。Hibernate 的 in 运算符还有另外一个用途,可以像在普通的 SQL 语句中那样来使用 in 运算符以给定某个属性可能取值的列表,也可以按这里采用的方式来使用 in。这个语句是告诉 Hibernate,我们感兴趣的曲目是其 artists 集合中含有特定艺人的那些曲目。为了调用这一查询,需要对 print-TrackSummary()做点修改,如例 9-20 所示。
例 9-20:改进 printTrackSummary(),以处理特定艺人的曲目
/**
*Print summary information about tracks associated with an artist.
*
*@param artist the artist in whose tracks we're interested.
*@param session the Hibernate session that can retrieve data.
**/
public static void printTrackSummary(Artist artist, Session session){
Query query=session.getNamedQuery("com.oreilly.hh.trackSummary");
query.setParameter("artist",artist);
Object[]results=(Object[])query.uniqueResult();
System.out.println("Summary of tracks by"+artist.getName()+':');
System.out.println("Total tracks:"+results[0]);
System.out.println("Shortest track:"+results[1]);
System.out.println("Longest track:"+results[2]);
}
没多加什么,对吧?最后,调用该方法的那行代码需要用一个参数来指定一个艺人对象。我们可以再次使用 CreateTest.java 中方便的 getArtist()方法。修改 QueryTest.java 的 main()方法中对该方法的调用代码,使其如例 9-21 所示。
例 9-21:调用已改进的 print, TrackSummary()
……
System.out.println("Track:"+title+"[ID="+id+']');
}
printTrackSummary(CreateTest.getArtist("Samuel Barber",
false, session),session);
}finally{
//No matter what, close the session
……
现在,当你执行 ant qtest 时,就会看到类似例 9-22 的信息。
例 9-22:运行摘要查询,以取得艺人 Samuel Barber 的所有曲目
qtest:
[java]Track:Video Killed the Radio Star[ID=2]
[java]Track:Test Tone 1[ID=7]
[java]Track:Russian Trance[ID=1]
[java]Track:Never Turn Your Back on Mother Earth[ID=12]
[java]Track:Motherless Child[ID=13]
[java]Track:In a Manner of Speaking[ID=9]
[java]Track:Gone[ID=11]
[java]Summary of tracks by Samuel Barber:
[java]Total tracks:2
[java]Shortest track:00:06:35
[java]Longest track:00:07:39
发生了什么事
注意:试着以普通的 SQL 做类似的事!
这根本不费吹灰之力,因此值得花点时间来欣赏一下 Hibernate 为我们做了多少事。我们调用的 getArtist()方法会返回与"Samuel Barber"对应的 Artist 实例,再将整个实例对象作为命名参数传递给 HQL 查询,而 Hibernate 也知道应该如何使用 Artist 对象的 id 属性和 TRACK_ARTISTS 表,把连接查询放在一起,以实现我们在例 9-10 中简单描述的那种复杂情况。
得到的结果反映出示例数据中那两个艺人相互混合的"Adagio for Strings"曲目。因为它们都超过了 5 分钟,所以没有出现在曲目列表中。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论