首页 > 代码库 > Hibernate对原生sql处理及结果集和VO的映射

Hibernate对原生sql处理及结果集和VO的映射

昨天解决一个看似很简单的需求,

我有一个类似下面的table(info_table),是收集产品使用的机型信息:

id

type

model

1

nokia

xxx1

2

nokia

xxx2

3

Motorola

yyyy1

4

Motorola

yyyy2

5

Motorola

yyyy3

要实现一个前台展示的页面:

type

countType

nokia

2

Motorola

3

就这么简单的功能。相信稍微熟悉sql的人,马上就可以写出此实现。很惭愧的说,我的心里感觉很简单,由于很久没怎么深入接触sql了,也费了一番周折...

selecttype,count(*) as countType from info_table group by Type order bycountType desc

实现上面的功能。

如何放到功能(struts2.3.x,spring3.1.x,hibernate4.x)集成的环境中处理?一步一步看:

首先从dao层:

@Override
publicList<CountVO> getAllHandleCount(){
Sessionsession =sessionFactory.getCurrentSession();
Stringhql ="selecttype,count(*) as countType from info_table group by Type order bycountType desc";
Queryquery = session.createQuery(hql);
@SuppressWarnings("unchecked")
List<CountVO>list = query.list();
returnlist;
}

再次server...

最后action层;

@Autowired
privateHandleCountServicehandleCountService;
privateIntegercurrentPage= 1;
privateIntegerpageSize= 10;
privateIntegertotalCount;
privateIntegertotalPage;

privateList<CountVO>handleCountVO;
/*
* handle count at 2014-12-04
*
*/
publicString HandleCountQueryAll() throwsIOException{
handleCountVO=handleCountService.getAllPage(currentPage,pageSize);
totalCount=handleCountService.getAllHandleCount().size();
totalPage= (totalCount+pageSize- 1) /pageSize;
returnSUCCESS;
}
……
get/set方法

由于返回的结果不是Hibernate管理的bean,所以理所当然的想到写个VO去接纳返回结果集。

CountVO.java

publicclassCountVO {
privateString type;
privateIntegercountUser;
publicString getType(){
returntype;
}
publicvoidsetType(Stringtype){
this.type=type;
}
publicInteger getCountUser() {
returncountUser;
}
publicvoidsetCountUser(Integer countUser) {
this.countUser= countUser;
}
}

前台直接通过传递ListBean通过struts标签来实现:

xxxx.jsp

…
<s:iteratorvalue=http://www.mamicode.com/"handleCountVO">>

整个流程配置完成。对我来说看似没问题,但是实际不是这样的...…


问题1

action层明明看到有list值,传到jsp层就是不显示,后debug跟到jsp,发现<s:iterator></s:iterator>也是可以循环的,可“奇怪”的就是不显示。

经过一番折腾,才发现经过sql获得的List不是“理所当然“的List<CountVO>而是List<Object>,其里面的值不是我想的CountVO中的typecountUser,而是[0],[1]


需要找方法解决这个问题,很简单的一个解决方法-----转换一下就可以了,我不想这样做,想弄清楚这个问题。


由于没开vpn,暂时baidu查查。

发现:

1)有个createSQLQuery和一直用的createQuery不同,因为CountVO不属于Hibernate管理的bean,不对应实体表,这个语句可能使用,最主要的还在后面;

createQuery用的hql语句进行查询,createSQLQuerysql语句查询;
前者以hibernate生成的Bean为对象装入list返回;
后者则是以对象数组进行存储;

所以使用createSQLQueryhibernate生成的Bean为对象装入list返回,可以直接转换对象 

Query query = session.createSQLQuery(sql).addEntity(XXXXXXX.class); 
XXXXXXX 
代表以hibernate生成的Bean的对象,也就是数据表映射出的Bean

(以上方法,只是介绍使用原生sql查询结果映射为hibernatebean方法,不能解决此问题)

2createSQLQuery后可以有这样的方法:setResultTransformer(...)


 Query

setResultTransformer(ResultTransformer transformer) 
          Seta strategy for handling the query results.

(只能google一下了)

Query setResultTransformer(ResultTransformer transformer)
Seta strategy for handling the query results. This can be used tochange "shape" of the query result.
Parameters:
transformer -The transformer to apply
Returns:
this(for method chaining)

这个函数功能:设置处理查询结果集的策略。

参数ResultTransformer定义:

public interface ResultTransformerextends Serializable

Implementorsdefine a strategy for transforming query results into the actualapplication-visible query result list.

setResultTransformer的执行者,转换查询结果到实际应用的结果列表。
ResultTransformer是个接口,通过hibernate3.3.xdoc文档可以看到其有多种实现类。

在一些博客中看到最多的是:Transformers.aliasToBean()

static ResultTransformer

aliasToBean(Class target) 
          Createsa result transformer that will inject aliased values intoinstances of Class via property methods or fields.

hibernate3.3.xdoc文档也看到:

org.hibernate.transform 
ClassAliasToBeanResultTransformer

java.lang.Object
  extended by org.hibernate.transform.AliasToBeanResultTransformer


中构造函数:
AliasToBeanResultTransformer(Class resultClass) 

也可以满足需求。

那就开始做吧-------可以完美解决

问题2

sql转换的一个小问题,也列到这吧,不让问题1孤单的存在着:

前面"selecttype,count(*) as countType from info_table group by Type order bycountType desc";

countcountVOcountType类型问题

IllegalArgumentExceptionin class: com.xxx.bean.CountVO, setter method of property: countUser

2014-12-0511:39:51,708 ERROR HHH000091: Expected type:java.lang.Integer,actual value: java.math.BigInteger

2014-12-0511:39:52,337 ERROR Exception occurred during processing request:IllegalArgumentExceptionoccurred while calling setter of com.xxx.bean.CountVO.countUser

org.hibernate.PropertyAccessException:IllegalArgumentExceptionoccurred while calling setter of com.xxx.bean.CountVO.countUser

类型不匹配,sqlcount(*)需要对应类型为java.math.BigInteger,那就把CountVO.javacountUser转为其类型。

解决此问题。


参考:

https://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/transform/ResultTransformer.html

https://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/transform/AliasToBeanResultTransformer.html

http://blog.163.com/charm_888/blog/static/608350020107254126654/

http://langgufu.iteye.com/blog/1565397


Hibernate对原生sql处理及结果集和VO的映射