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="handleCountVO">
<tr>
<td><s:propertyvalue="type"/></td>
<td><s:propertyvalue="countUser"/></td>
</tr>
</s:iterator>
…

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

问题1:

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

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

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

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

发现:

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

createQuery用的hql语句进行查询,createSQLQuery用sql语句查询;

前者以hibernate生成的Bean为对象装入list返回;

后者则是以对象数组进行存储;

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

Query query = session.createSQLQuery(sql).addEntity(XXXXXXX.class);

XXXXXXX 代表以hibernate生成的Bean的对象,也就是数据表映射出的Bean。

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

2)createSQLQuery后可以有这样的方法: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
  org.hibernate.transform.AliasToBeanResultTransformer
中构造函数:
AliasToBeanResultTransformer(Class resultClass) 

也可以满足需求。

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

问题2:

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

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

中count和countVO中countType类型问题。

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

类型不匹配,sql中count(*)需要对应类型为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

时间: 2024-08-01 04:37:28

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

hibernate使用原生SQL查询返回结果集的处理

今天没事的时候,看到公司框架里有一个用原生SQL写的函数,说实在以前自己也干过这事,但好久都没有用,都忘得差不多了,现在基本都是用的hql语句来查询结果.hibernate中使用createSQLQuery拉来来实现SQL语句的查询,具体用法:session.createSQLQuery(sql),对于用SQL返回的结果集是一个什么样的结果集都毫无记忆.自己查了下,才知道,原来是返回一个Object类型数组的list集合,而其中Object类型的数组里的值则与sql语句中的查询项相对应,如果是s

Hibernate SQLQuery 原生SQL 查询及返回结果集处理-1

第一篇:官方文档的处理方法,摘自官方 在迁移原先用JDBC/SQL实现的系统,难免需要采用hibernat native sql支持. 1.使用SQLQuery hibernate对原生SQL查询执行的控制是通过SQLQuery接口进行的. Session.createSQLQuery(); 1.1标量查询 最基本的SQL查询就是获得一个标量(数值)的列表. sess.createSQLQuery("SELECT * FROM CATS").list(); sess.createSQL

Hibernate 的原生 SQL 查询

Hibernate除了支持HQL查询外,还支持原生SQL查询.         对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口.该接口是Query接口的子接口.         执行SQL查询步骤如下:         1.获取Hibernate Session对象         2.编写SQL语句         3.通过Session的createSQLQuery方法创建查询对象         4.调用SQ

Hibernate 使用原生SQL查询无法使用别名问题

最近遇到一个问题就是Hibernate在使用原生SQL进行多表联合查询别名的问题,一直报错,说是找不到某列,经过向别人咨询最后得出了解决方案 需要向数据库连接字符串中加入属性,具体如下 common.db.driverClassName=com.mysql.jdbc.Driver common.db.url=jdbc:mysql://10.10.11.8:3306/cm_mini_1?useOldAliasMetadataBehavior=true common.db.username=user

Hibernate使用原生SQL(转载)

本文转载,出处如下:http://bhdweb.iteye.com/blog/801084 HQL尽管容易使用,但是在一些复杂的数据操作上功能有限.特别是在实现复杂的报表统计与计算,以及多表连接查询上往往无能为力,这时可以使用SQL(Native SQL)实现HQL无法完成的任务. 1.使用SQL查询 使用SQL查询可以通过两种方式来实现: (1).利用Hibernate提供的SQLQuery对象执行.即可以通过Session对象的createSQLQuery()方法获取.如: String s

Hibernate使用原生SQL语句进行无关联多表查询

背景:有两个表:CpCg与CpGg需要进行多表查询 因为CpGg表设计到与另外的表也有联系,因此师兄没有关联此两个表,只是用字段进行逻辑关联,CpGg表的cp字段与CpCg表的id字段逻辑关联 首先确保hibernate配置文件配置完成,配置文件如下:(一些与本人项目相关的关键字段已隐去) <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC

Hibernate SQLQuery原生SQL查询

使用Hibernate SQLQuery进行查询时,如果有两个列的列明相同,那么在取值时,Hibernate会取第一个同名列的值(在SQLPlus中会自动在列明后面跟上写字符进行区分).如: 1.SQL语句 SELECT * FROM (SELECT 'A' A, 'B' B FROM DUAL) TEMP_A, (SELECT 'C' A, 'D' B FROM DUAL) TEMP_B 2.Sqlplus查询结果: 3.Hibernate SQLQuery查询结果:

hibernate 执行原生sql 返回实体list对象

String sql="select gc.* from eportal_goods_category gc "+ " inner JOIN "+ " eportal_goods g on gc.id=g.goods_category_id "+ " INNER JOIN "+ " eportal_seller se on  g.supplier_id=se.id "+ " where se.id

Hibernate执行原生SQL

1.查询指定字段 public List<Object[]> getUseList( Integer index, Integer offset, String state, String search ){ String sqlSelect = "select user_id, user_name "; String sql = sqlSelect + " from users where user_status in (:state) limit :index