今天徒弟用到了一句复杂的查询语句。。。。结果执行报错,但是在SQL中执行没有问题,于是来求助我了。。。
语句的HQL/SQL格式如下:
select count(1) ,cxltype,sum(dzsje),sum(iperson)from (select xl.cxltype,g.iperson,(select sum(y.dzsje) from Ysklist as y where y.cykpid = g.cregno) as dzsje from Guestreg as g,Xl as xl where g.xluuid = xl.uuid ) as t where …… group by t.cxltype
结果执行出错,最终发现,HQL无法支持from后面跟子查询的方式,网上查了N多资料,发现遇到这个问题的人还真是不少,但每一个相关的问题帖都没有满意的答复,甚至于多数都是没有跟帖的。。。。
一阵心寒,hibernate叱咤风云,竟然对这个支持如此之弱?虽然这个语句可以通过另外的方法来做(比如建视图或者直接使用SQL来做),但总是不甘心,于是又开始查阅各处资料,最后找到了思路,觉得既然HQL不支持,那么只能把这种子查询封装为对象来做了,那么肯定是需要hbm配置这种临时的子查询对象的,于是开始着手hbm配置的资料中查,hbm中配置对象的都是class标签,开始把范围缩小,针对hbm的class标签的属性资料开始翻查,找到了几个比较可能的属性,where、subselect、mutable、entity-bean,貌似这些都可能跟临时对象有关。。。
于是反复尝试,并继续翻查资料
最终在Hibernate reference 3.2.0 ga 正式版中文参考手册中找到了一些比较可靠的资料:
你可以使用class
元素来定义一个持久化类:
<class
name="ClassName"
table="tableName"
discriminator-value="discriminator_value"
mutable="true|false"
schema="owner"
catalog="catalog"
proxy="ProxyInterface"
dynamic-update="true|false"
dynamic-insert="true|false"
select-before-update="true|false"
polymorphism="implicit|explicit"
where="arbitrary sql where condition"
persister="PersisterClass"
batch-size="N"
optimistic-lock="none|version|dirty|all"
lazy="true|false"
entity-name="EntityName"
check="arbitrary sql check condition"
rowid="rowid"
subselect="SQL expression"
abstract="true|false"
node="element-name"
/>
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
(16) |
|
(17) |
|
(18) |
|
(19) |
|
(20) |
|
(21) |
|
注意其中红色的字体,这就是关键之处,往下我找到了相关的内容:
对Hibernate映射来说视图和表是没有区别的,这是因为它们在数据层都是透明的( 注意:一些数据库不支持视图属性,特别是更新的时候)。有时你想使用视图,但却不能在数据库 中创建它(例如:在遗留的schema中)。这样的话,你可以映射一个不可变的(immutable)并且是 只读的实体到一个给定的SQL子查询表达式:
<class name="Summary">
<subselect>
select item.name, max(bid.amount), count(*)
from item
join bid on bid.item_id = item.id
group by item.name
</subselect>
<synchronize table="item"/>
<synchronize table="bid"/>
<id name="name"/>
...
</class>
定义这个实体用到的表为同步(synchronize),确保自动刷新(auto-flush)正确执行, 并且依赖原实体的查询不会返回过期数据。<subselect>
在属性元素 和一个嵌套映射元素中都可见。
显然这就是我一直在找的东东了,hibernate支持自身建立视图,而不需要依赖于数据库。。虽然它本身的说法这是用来替代视图的,但其实这就是带子查询的sql,看我们最终的配置结果。
临时子查询视图Bean[其中第二个非默认的构造函数是不能少的,不然对象无法创建]:
public class TestBean {
private Integer id;
private String cxltype;
private Integer iperson;
private Double dzsje;
public TestBean(){}
public TestBean(String cxltype, Integer iperson, Double dzsje) {
super();
this.cxltype = cxltype;
this.iperson = iperson;
this.dzsje = dzsje;
}
public String getCxltype() {
return cxltype;
}
public void setCxltype(String cxltype) {
this.cxltype = cxltype;
}
public Integer getIperson() {
return iperson;
}
public void setIperson(Integer iperson) {
this.iperson = iperson;
}
public Double getDzsje() {
return dzsje;
}
public void setDzsje(Double dzsje) {
this.dzsje = dzsje;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
TestBean的hbm配置:
<hibernate-mapping> <class name="TestBean" mutable="false"> <subselect> select xl.cxltype,g.iperson,(select sum(y.dzsje) from Ysklist as y where y.cykpid = g.cregno) as dzsje from Guestreg as g,Xl as xl where g.xluuid = xl.uuid </subselect> <synchronize table="Guestreg"/> <synchronize table="Xl"/> <id name="id" type="integer"> <column name="id" /> <generator class="identity" /> </id> <property name="cxltype" type="string"> <column name="cxltype"></column> </property> <property name="iperson" type="integer"> <column name="iperson"></column> </property> <property name="dzsje" type="double"> <column name="dzsje"></column> </property> </class> </hibernate-mapping>
HQL语句:
select t.cxltype,sum(t.dzsje),sum(t.iperson) from TestBean as t where …… group by t.cxltype
Hibernate生成的SQL语句:
Hibernate: select testbean0_.cxltype as col_0_0_, sum(testbean0_.dzsje) as col_1_0_, sum(testbean0_.iperson) as col_2_0_ from (
select xl.cxltype,g.iperson,(select sum(y.dzsje) from Ysklist as y where y.cykpid = g.cregno) as dzsje
from Guestreg as g,Xl as xl
where g.xluuid = xl.uuid
) testbean0_ where 1=1 group by testbean0_.cxltype
可以看得出来,这就是文章最开始要完成的SQL子查询语句
到此告一段落,花了我半个下午的时间搞定。。。
而这个问题也是很久以前我一开始就怀疑hibernate的HQL灵活性的一个困惑,一直觉得Hibernate在多表查询上是一个弱项,但我也一直没有找时间去深究过,而经过这次问题,让我对Hibernate又多认识了一些。。呵呵,以后可以更放心的去用它了