Hibernate Predicates无效路径问题:编译正常运行报错求助
问题场景回顾
你定义了三个实体:Event、作为子类的MessageEvent(已正确配置鉴别器值),以及Message。MessageEvent通过如下注解关联Message:
@ManyToOne(optional = false, cascade = CascadeType.REMOVE) @JoinColumn(name = "MESAGE_ID", nullable = false) private Message message;
为了查询关联Message id为2的MessageEvent,你写出了这段编译正常但运行报错的Predicate代码:
cb.equal(cb.treat(root, MessageEvent.class).join(MessageEvent_.message, JoinType.LEFT).get(Message_.id), 2)
运行时Hibernate抛出了HQL路径解析错误:
5:40:59,891 ERROR [org.hibernate.hql.internal.ast.ErrorCounter] (default task-2) Invalid path: 'generatedAlias1.id': Invalid path: 'generatedAlias1.id'
at org.hibernate//org.hibernate.hql.internal.ast.util.LiteralProcessor.lookupConstant(LiteralProcessor.java:114)
at org.hibernate//org.hibernate.hql.internal.ast.tree.DotNode.resolve(DotNode.java:214)
at org.hibernate//org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:109)
at org.hibernate//org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:104)
at org.hibernate//org.hibernate.hql.internal.ast.HqlSqlWalker.resolve(HqlSqlWalker.java:1033)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1286)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4699)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:4169)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2134)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2084)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2084)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2084)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2084)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2059)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2059)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:813)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:607)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:311)
at org.hibernate//org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:259)
你的测试环境覆盖Java 8/10(OpenJDK)、Wildfly 10/12,且相同逻辑在EclipseLink中能正常运行。
问题根源
这是Hibernate的框架缺陷,和你的代码无关。当你在cb.treat()之后直接链式调用join()时,Hibernate的HQL解析器无法正确跟踪关联属性的路径,导致后续获取id时抛出路径无效的错误。而EclipseLink的解析器在处理这种链式调用时逻辑更完善,所以能正常执行。
修复方案
只需要拆分链式调用,先把类型转换后的根对象赋值给一个变量,再执行join操作,Hibernate就能正确解析路径了:
// 先将Root转换为MessageEvent类型并赋值给变量 Root<MessageEvent> messageEventRoot = cb.treat(root, MessageEvent.class); // 基于转换后的根对象执行join并构建Predicate cb.equal(messageEventRoot.join(MessageEvent_.message, JoinType.LEFT).get(Message_.id), 2);
这个小改动能让Hibernate正确生成对应的HQL和SQL查询,解决路径解析的问题。
内容的提问来源于stack exchange,提问作者Juraj Mlich

