HQL查询用ResultTransformer转CarDTO报错:找不到setter方法
嘿,我来帮你搞定这个Hibernate报错的问题!首先咱们得先搞明白为什么会出现Could not find setter for 1 on class CarDTO这个错误。
错误原因分析
你写的HQL查询返回的是一个二元结果数组:第一个元素是计算出来的tireCount整数,第二个是完整的Car实体对象。当你调用Query.setResultTransformer(CarDTO.class)时,Hibernate会默认把结果数组的每个元素按位置索引(从1开始)去匹配DTO类的setter方法——它会尝试找set1()方法来设置第一个元素的值,但你的CarDTO里根本没有这个方法,自然就报错了。而且它也不知道该怎么把第二个元素(Car实例)的属性映射到CarDTO继承的那些属性上。
解决方案(推荐两种)
1. 构造函数映射(类型安全,最省心)
给你的CarDTO添加一个带参数的构造函数,参数顺序和HQL查询结果的顺序一致:
public class CarDTO extends Car { private Integer tireCount; // 添加这个构造函数 public CarDTO(Car car, Integer tireCount) { // 把Car的属性复制到CarDTO里,可手动赋值或用BeanUtils等工具简化 this.setColor(car.getColor()); this.setTires(car.getTires()); this.tireCount = tireCount; } // 原有的getter、setter和其他代码... }
然后修改你的HQL查询,直接在查询里构造CarDTO(注意要写全类名):
select new com.yourpackage.CarDTO(e, (select cast(nvl(sum(d.count),0) as integer) from e.tires d)) from Car e
这样查询的时候,Hibernate会直接调用你定义的构造函数创建CarDTO实例,不需要再调用setResultTransformer,直接query.list()就能得到List<CarDTO>了。
2. 使用AliasToBeanResultTransformer(适合不想加构造函数的场景)
如果你不想给CarDTO加构造函数,可以改用AliasToBeanResultTransformer,但需要调整HQL查询,给每个结果项起别名,并且确保CarDTO有对应的setter方法(包括继承自Car的属性的setter):
首先修改HQL,把Car的属性和tireCount都明确查出来并起别名:
select e.color as color, e.tires as tires, (select cast(nvl(sum(d.count),0) as integer) from e.tires d) as tireCount from Car e
然后设置ResultTransformer:
Query query = session.createQuery(hql); query.setResultTransformer(new AliasToBeanResultTransformer(CarDTO.class)); List<CarDTO> carDTOs = query.list();
这种方法需要确保HQL里的别名和CarDTO的属性名完全一致,Hibernate会通过setter方法自动赋值。
为什么原来的写法行不通?
再强调一下:你的原HQL返回的是Object[],其中第一个元素是tireCount,第二个是Car对象。Hibernate的默认ResultTransformer(用类名的那种)会把数组的每个元素按位置索引去匹配setter,而不是把Car对象的属性拆开来映射到DTO的继承属性上,所以才会找不到set1()方法。
内容的提问来源于stack exchange,提问作者Javad Kargar

