Hibernate原生SQL查询报ClassCastException 无法转为自定义实体类
异常触发原因
- 从Hibernate原生SQL的执行机制来看,未配置结果映射的
createSQLQuery()调用,默认会将每一行数据库记录封装为一个Object[]类型的数组,最终返回的List集合中,所有元素的类型都是Object数组,而非预期的Urunler实体对象。 - 代码中直接将上述返回的List强制转换为
List<Urunler>类型时,本质是试图把每个Object数组元素硬转成Urunler实例。由于Object数组和Urunler类不存在继承或实现关系,Java类型校验不通过,就会抛出日志中提示的java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.pizzaweb.model.Urunler——日志里的[Ljava.lang.Object就是JVM对Object数组的标准类型签名。 - 额外提示:方法签名声明返回
List<UrunList>类型,但当前逻辑操作的是Urunler类对象,如果两个类没有继承关系,即使修复了原生SQL的映射问题,后续返回时还会触发新的类转换异常。
对应修复方案
- 方案1:在原生SQL查询中显式绑定实体映射,让Hibernate自动完成结果集封装(推荐使用)
调用SQL查询接口时,通过addEntity()方法指定结果行对应的实体类,让Hibernate自动将数据库列的值映射到Urunler的属性上,修改后的代码参考:
使用注意:拼接SQL时的查询列必须和Urunler类中@Column注解映射的字段一一对应,尽量避免查询部分字段导致的映射错位。// 注意SQL中查询的列要和Urunler实体映射的字段完全匹配,推荐直接查询全字段 String query = "SELECT * FROM Urunler WHERE stok > 0 AND kategori_id = ? " + "ORDER BY id OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; List<Urunler> result = session.createSQLQuery(query) .addEntity(Urunler.class) // 显式指定实体映射 .setParameter(0, kategoriId) .setParameter(1, offset) .setParameter(2, pageSize) .list(); - 方案2:手动遍历原生查询返回的Object数组结果,逐行封装为实体对象
如果不需要Hibernate自动映射,可以保留默认的查询返回结果结构,手动完成对象转换,参考代码:
这种方案维护成本较高,SQL字段顺序调整时很容易出现赋值错位,仅适用于查询字段较少、不需要频繁调整SQL的场景。List rawResult = session.createSQLQuery(query).list(); List<Urunler> urunList = new ArrayList<>(); for (Object row : rawResult) { Object[] rowData = (Object[]) row; // 逐行取出Object数组 Urunler urun = new Urunler(); // 按照SQL中查询的字段顺序,逐字段赋值给实体属性 urun.setId((Integer) rowData[0]); urun.setUrunAd((String) rowData[1]); urun.setStok((Integer) rowData[2]); urun.setKategoriId((Integer) rowData[3]); // 补充剩余属性的赋值逻辑 urunList.add(urun); } - 适配方法签名要求:拿到
List<Urunler>结果后,根据UrunList类的字段定义,逐行将Urunler的属性复制到UrunList实例中,最终返回符合方法签名要求的List<UrunList>即可。
内容的提问来源于stack exchange,提问作者Mustafa Gürses
相关产品推荐
相关产品推荐

