Hibernate对原生sql处理及结果集报错:Expected type: java.lang.Integer, actual value: java.math.BigInteger

本文探讨了在Hibernate框架下执行SQL查询并正确映射结果的问题,包括实体类属性类型的匹配、使用createSQLQuery及setResultTransformer进行结果转换的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于Hibernate执行sql查询方法,映射实体对象报错Expected type: java.lang.Integer, actual value: java.math.BigInteger

实体类ChannelTree

package com.han.cms.dto;

import java.math.BigInteger;

/**
 * 系统栏目树对象
 * @author Administrator
 *
 */
public class ChannelTree {
	private Integer id;
	private String name;
	private Integer pid;//映射报错,将Integer类型改成BigInteger类型即可

	public ChannelTree() {

	}

	public ChannelTree(Integer id, String name, Integer pid) {
		this.id = id;
		this.name = name;
		this.pid = pid;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getPid() {
		return pid;
	}

	public void setPid(Integer pid) {
		this.pid = pid;
	}

}

service查询方法

Override
	public List<ChannelTree> getChannelTreeDatas() throws Exception{
		String sql="select c.id,c.name,IFNULL(c.pid,0) as pid from t_channel c";
		List<ChannelTree> channelTrees = this.channelDao.findListBySql(sql, ChannelTree.class, false);
		channelTrees.add(0,new ChannelTree(0,"系统栏目管理",new BigInteger("-1")));
		return channelTrees;
	}


test测试类方法

@Test
	public void getChannelTrees() throws Exception{
		System.out.println(this.channelService.getChannelTreeDatas().size());
	}

运行结果报错:

Hibernate: select c.id,c.name,IFNULL(c.pid,0) as pid from t_channel c
15:39:55,758 ERROR BasicPropertyAccessor:117 - HHH000123: IllegalArgumentException in class: com.han.cms.dto.ChannelTree, setter method of property: pid
15:39:55,760 ERROR BasicPropertyAccessor:118 - HHH000091: Expected type: java.lang.Integer, actual value: java.math.BigInteger

修改之后ChannelTree

package com.han.cms.dto;

import java.math.BigInteger;

/**
 * 系统栏目树对象
 * @author Administrator
 *
 */
public class ChannelTree {
	private Integer id;
	private String name;
	private BigInteger pid;

	public ChannelTree() {

	}
    
	public ChannelTree(Integer id, String name, BigInteger pid) {
		this.id = id;
		this.name = name;
		this.pid = pid;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public BigInteger getPid() {
		return pid;
	}

	public void setPid(BigInteger pid) {
		this.pid = pid;
	}
    
}
service查询方法

	@Override
	public List<ChannelTree> getChannelTreeDatas() throws Exception{
		String sql="select c.id,c.name,IFNULL(c.pid,0) as pid from t_channel c";
		List<ChannelTree> channelTrees = this.channelDao.findListBySql(sql, ChannelTree.class, false);
		channelTrees.add(0,new ChannelTree(0,"系统栏目管理",new BigInteger("-1")));
		return channelTrees;
	}


测试类

@Test
	public void getChannelTrees() throws Exception{
		System.out.println(this.channelService.getChannelTreeDatas().size());
	}

运行结果:

Hibernate: select c.id,c.name,IFNULL(c.pid,0) as pid from t_channel c
4

具体的解释可以参考以下的

我有一个类似下面的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层:

[java]  view plain  copy
  1. @Override  
  2. publicList<CountVO> getAllHandleCount(){  
  3. Sessionsession =sessionFactory.getCurrentSession();  
  4. Stringhql ="selecttype,count(*) as countType from info_table group by Type order bycountType desc";  
  5. Queryquery = session.createQuery(hql);  
  6. @SuppressWarnings("unchecked")  
  7. List<CountVO>list = query.list();  
  8. returnlist;  
  9. }  

再次server...

最后action层;

[java]  view plain  copy
  1. @Autowired  
  2. privateHandleCountServicehandleCountService;  
  3. privateIntegercurrentPage= 1;  
  4. privateIntegerpageSize= 10;  
  5. privateIntegertotalCount;  
  6. privateIntegertotalPage;  
  7.   
  8. privateList<CountVO>handleCountVO;  
  9. /* 
  10. * handle count at 2014-12-04 
  11. * 
  12. */  
  13. publicString HandleCountQueryAll() throwsIOException{  
  14. handleCountVO=handleCountService.getAllPage(currentPage,pageSize);  
  15. totalCount=handleCountService.getAllHandleCount().size();  
  16. totalPage= (totalCount+pageSize- 1) /pageSize;  
  17. returnSUCCESS;  
  18. }  
  19. ……  
  20. get/set方法  

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

CountVO.java

[java]  view plain  copy
  1. publicclassCountVO {  
  2. privateString type;  
  3. privateIntegercountUser;  
  4. publicString getType(){  
  5. returntype;  
  6. }  
  7. publicvoidsetType(Stringtype){  
  8. this.type=type;  
  9. }  
  10. publicInteger getCountUser() {  
  11. returncountUser;  
  12. }  
  13. publicvoidsetCountUser(Integer countUser) {  
  14. this.countUser= countUser;  
  15. }  
  16. }  

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

xxxx.jsp

[html]  view plain  copy
  1. …  
  2. <s:iteratorvalues:iteratorvalue="handleCountVO">  
  3. <tr>  
  4. <td><s:propertyvalues:propertyvalue="type"/></td>  
  5. <td><s:propertyvalues:propertyvalue="countUser"/></td>  
  6. </tr>  
  7. </s:iterator>  
  8. …  

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


问题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
  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




<think>好的,用户的问题是问在Java中,Expectedjava.lang.Long<2>,Actualjava.lang.Integer<2>有什么区别。我需要先理解这两个类型的不同,然后解释它们的区别。 首先,Long和Integer都是Java的包装类,分别对应基本类型long和int。虽然它们的值都是2,但类型不同。用户可能是在测试或者调试时遇到了类型不匹配的问题,比如断言失败,因为预期类型是Long,实际得到的是Integer。 接下来,我需要从几个方面分析区别:类型不同、内存存储、自动装箱的区别、比较时的行为,以及在方法调用或泛型中的影响。 类型不同是最基本的,Long是Long类的实例,IntegerInteger类的实例,它们的父类都是Number,但具体类型不同。内存存储方面,Long占8字节,Integer占4字节,但作为对象,它们的对象头可能有差异。自动装箱时,基本类型long会被装箱成Long,int装箱成Integer,所以如果代码中错误地将int装箱,就会得到Integer而不是预期的Long。 比较时,如果直接用==比较对象,会比较引用而不是值,所以即使值相同,类型不同的话==会返回false。而使用equals方法,Long的equals方法会检查参数是否是Long类型,所以如果传入Integer,equals会返回false。例如,new Long(2).equals(new Integer(2))结果是false,因为类型不同。 在方法调用中,如果方法参数是Long类型,传入Integer会编译错误,需要显式转换。泛型中如果指定了类型为Long,传入Integer也会类型不匹配。 用户可能遇到的场景是单元测试中的断言失败,比如使用JUnit的assertEquals时,预期是Long类型的2,实际得到的是Integer类型的2,这时候断言会失败,因为类型不同,equals方法返回false。 需要解释清楚类型差异导致的行为不同,特别是equals和==的比较结果,以及在实际开发中的影响,比如参数传递、泛型约束等。 现在需要组织这些点,用清晰的结构回答用户的问题,然后生成相关的问题。 </think>在Java中,`Expected: java.lang.Long<2>`(预期类型为`Long`,值为2)和`Actual: java.lang.Integer<2>`(实际类型为`Integer`,值为2)的核心区别在于**类型不同**,尽管它们的数值相同,但类型差异会导致一系列行为差异。具体区别如下: ### 1. 类型归属不同 - `Long`是`long`的包装类,继承自`Number`,最终继承`Object`; - `Integer`是`int`的包装类,同样继承自`Number`,但与`Long`是**不同的类**,彼此之间无继承关系。 因此,即使数值相同,它们是**不同类型的对象实例**。 ### 2. 内存存储与范围不同 - `Long`对应基本类型`long`,占8字节(64位),取值范围为`-2^63 ~ 2^63-1`; - `Integer`对应基本类型`int`,占4字节(32位),取值范围为`-2^31 ~ 2^31-1`。 虽然此处数值均为2(在两者范围内),但类型决定了它们能表示的数值范围不同。 ### 3. 比较行为不同 - **`==`比较**:比较的是对象引用地址。由于`Long`和`Integer`是不同类的实例,即使数值相同,`new Long(2) == new Integer(2)`结果为`false`; - **`equals()`方法**:`Long`的`equals()`方法会先检查参数是否是`Long`类型,若不是直接返回`false`(同理`Integer`的`equals()`也会检查类型)。因此: ```java new Long(2).equals(new Integer(2)); // 结果为false(类型不匹配) new Long(2).equals(new Long(2)); // 结果为true(类型和值均匹配) ``` ### 4. 方法参数或泛型约束的影响 若代码中通过方法参数或泛型明确指定类型(如`void method(Long value)`或`List<Long>`),则传入`Integer`类型会直接导致**编译错误**(除非显式类型转换)。例如: ```java List<Long> list = new ArrayList<>(); list.add(2); // 编译错误:2自动装箱为Integer,无法直接存入List<Long> list.add(2L); // 正确:2L是long类型,自动装箱为Long ``` ### 5. 常见触发场景(如单元测试断言失败) 在单元测试(如JUnit)中,若预期结果是`Long`类型的2,而实际结果是`Integer`类型的2,断言(如`assertEquals(expected, actual)`)会失败。因为`assertEquals`本质是通过`equals()`比较,而类型不同会导致`equals()`返回`false`。 ### 总结 两者的核心差异是**类型不同**,这会导致比较行为、参数传递、泛型约束等场景下的不兼容,即使数值相同也无法直接视为等价。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值