Hibernate4迁移至Hibernate5时Criteria查询报ORA-00904错误求助
问题代码
public Integer getCount(QueryBuilder query) { Criteria criteria = getDao().buildCriteria(Summary.class, query); criteria.setProjection(count("id")); return ((Long) criteria.list().get(0)).intValue(); }
报错日志
ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - "ORA-00904: "THIS_"."CREATED_BY_USER_ID": invalid identifier"
ERROR controllers.UncaughtExceptionHandler - "Uncaught exception [org.hibernate.exception.SQLGrammarException] in handler [org.springframework.web.method.HandlerMethod] message [could not extract ResultSet > ORA-00904: "THIS_"."CREATED_BY_USER_ID": invalid identifier]"
org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63)Caused by: java.sql.SQLSyntaxErrorException: ORA-00904: "THIS_"."CREATED_BY_USER_ID": invalid identifier
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:450) at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:399)
Hibernate 4 到 5 的关键变化(对应此场景)
1. Criteria 投影与查询条件的关联处理逻辑变更
Hibernate 4中,设置投影(如count("id"))后,会自动忽略查询条件中未关联投影的字段/关联属性,不会将其加入生成的SQL。但Hibernate 5调整了这一行为:如果QueryBuilder中包含关联属性(比如CREATED_BY_USER_ID,可能是Summary关联的User实体属性)的查询条件,即使设置了投影,Hibernate 5仍会尝试在SQL中引入这些关联字段,若实体映射未正确配置该关联(或字段名不匹配),就会触发字段不存在的错误。
2. 关联查询的默认行为调整
- Hibernate 4中,仅查询主实体投影字段时,即使有关联条件,也可能不会主动JOIN关联表;而Hibernate 5会强制生成JOIN语句,若关联属性映射存在歧义(比如字段大小写错误、注解配置错误),就会抛出ORA-00904。
- 若
QueryBuilder中使用了createAlias或fetch操作关联其他实体,Hibernate 5的SQL生成逻辑更严格,任何映射错误都会直接暴露为语法异常。
3. 投影查询的校验规则升级
Hibernate 5对投影与查询条件的组合做了更严格的校验:Hibernate 4会自动优化SQL,仅保留投影字段和必要的条件字段;Hibernate 5则严格按照查询条件中的属性生成SQL,若条件中的属性对应数据库字段不存在(或别名错误),直接触发语法错误。
4. 表别名生成规则变更
Hibernate 5调整了Criteria查询的表别名生成逻辑,主表默认别名变为THIS_。如果实体映射或QueryBuilder中硬编码了旧版本的别名,会导致字段引用错误(不过此场景中THIS_是合法主表别名,问题核心还是关联属性处理)。
解决思路参考
- 检查
Summary实体映射:确认CREATED_BY_USER_ID是表直接字段还是关联实体属性,若是关联属性,需确保QueryBuilder使用正确的关联路径(如user.id而非直接CREATED_BY_USER_ID)。 - 清理投影无关的查询条件:设置
count("id")投影后,移除QueryBuilder中与计数无关的关联条件或属性引用,避免Hibernate生成不必要的JOIN。 - 显式指定关联策略:若必须保留关联条件,使用
createAlias并指定关联类型(如LEFT_JOIN),确保生成正确的SQL JOIN语句。
内容的提问来源于stack exchange,提问作者Michu93

