多表复杂查询转Java POJO遇Hibernate属性异常的解决咨询
嘿,这个坑我之前踩过!咱们先把问题根源说清楚,再给你几个符合Java规范的解决办法:
为什么会报错?
Hibernate的AliasToBeanResultTransformer(你应该用的是这个转换器吧?)默认是通过SQL查询结果的别名,去匹配POJO的setter方法,而且是严格大小写敏感的。
你原来的查询结果里,字段别名是ID(大写),但你的POJO里字段是id(小写驼峰),对应的setter是setId()。Hibernate会找setID()这个方法——显然你的POJO里没有,所以就抛出了PropertyNotFoundException。当你把POJO字段改成ID后,IDE自动生成的setter是setID(),刚好匹配上别名,所以不报错,但这确实违反了Java驼峰命名的规范。
符合规范的更佳处理方式
方法1:修改SQL查询的别名(最推荐)
直接把SQL里的别名ID改成id,让它和POJO的字段名(以及对应的setId()方法)匹配。比如:
原来的查询片段:
SELECT t.id AS ID, t.content AS CONTENT ...
改成:
SELECT t.id AS id, t.content AS content ...
这样Hibernate就能自动找到setId()、setContent()这些符合规范的setter方法,完美解决问题,还完全遵循Java命名规则。
方法2:用@SqlResultSetMapping显式映射(适合SQL别名不能改的场景)
如果因为某些原因(比如遗留系统、自动生成的SQL)没法修改别名,那可以用Hibernate的结果集映射注解,手动指定数据库列名(别名)和POJO字段的对应关系。
假设你的Feed是一个DTO,你可以这么做:
- 在
Feed类上添加映射注解:
import javax.persistence.SqlResultSetMapping; import javax.persistence.ConstructorResult; import javax.persistence.ColumnResult; @SqlResultSetMapping( name = "FeedResultSetMapping", classes = @ConstructorResult( targetClass = Feed.class, columns = { @ColumnResult(name = "ID", type = Long.class), // 对应SQL里的大写别名 @ColumnResult(name = "CONTENT", type = String.class), // 其他字段依次映射 } ) ) public class Feed { private Long id; private String content; // 必须要有和映射字段顺序一致的构造方法 public Feed(Long id, String content) { this.id = id; this.content = content; } // getter和setter(按需添加) }
- 然后在DAO里使用这个映射:
Session session = ...; Query query = session.createSQLQuery("你的复杂SQL语句") .setResultSetMapping("FeedResultSetMapping"); List<Feed> feedList = query.list();
这种方式不需要修改POJO的字段命名,也不用改SQL,通过显式映射解决匹配问题。
方法3:自定义ResultTransformer(不推荐,太繁琐)
如果上面两种都不适用,你还可以自己写一个ResultTransformer,手动处理字段名的大小写映射,但这种方式代码量比较大,维护起来麻烦,除非特殊情况不建议用。
内容的提问来源于stack exchange,提问作者user5636236

