
Hibernate 6 对 JPQL 中跨根实体(SqmRoot)的 JOIN 条件校验更严格,原在 Hibernate 5 中允许的“非直接关联根路径”JOIN 写法会触发 SqmQualifiedJoin predicate referred to SqmRoot other than the join's root 错误;正确做法是确保每个 JOIN ... ON 子句仅引用其左侧直接关联的根或前序 JOIN 结果,并按逻辑依赖顺序排列 JOIN。
hibernate 6 对 jpql 中跨根实体(sqmroot)的 join 条件校验更严格,原在 hibernate 5 中允许的“非直接关联根路径”join 写法会触发 `sqmqualifiedjoin predicate referred to sqmroot other than the join's root` 错误;正确做法是确保每个 `join ... on` 子句仅引用其**左侧直接关联的根或前序 join 结果**,并按逻辑依赖顺序排列 join。
Hibernate 6 引入了更严格的语义验证机制,尤其在处理 JOIN ... ON 子句时,要求 ON 条件中出现的所有标识符必须属于该 JOIN 的“左操作数”(即其直接关联的根或前序已 JOIN 的别名)。在你原始的 JPQL 中:
JOIN Mef mef ON mef.etabUajId = etab.id, TiMefAccueil nomenMef JOIN AepBanMef ban ON ((mef.code = ban.code and mef.mefRattachement = null) OR mef.mefRattachement = ban.code)
问题在于:JOIN AepBanMef ban 被写在了逗号分隔的 TiMefAccueil nomenMef 之后,但其 ON 条件却引用了 mef(属于前一个 JOIN Mef mef),而 Hibernate 6 认为 ban 的“所属根上下文”此时是 nomenMef(因语法上它紧邻 nomenMef 声明),导致 mef 被视为“非法跨根引用”。
✅ 正确修复方式是:将 JOIN AepBanMef ban 移至 mef 之后、且与 mef 形成连续 JOIN 链,使其 ON 条件自然归属 mef 的作用域:
@Query("SELECT etab " +
"FROM #{#entityName} etab " +
"JOIN Mef mef ON mef.etabUajId = etab.id " +
"JOIN AepBanMef ban ON (mef.code = ban.code AND mef.mefRattachement IS NULL) OR mef.mefRattachement = ban.code " +
"JOIN TiMefAccueil nomenMef " + // 注意:此处改为显式 JOIN(推荐),或保留逗号但确保位置合理
"WHERE (" +
"SUBSTRING(mef.code, 1, LENGTH(nomenMef.debutCodeMef)) = nomenMef.debutCodeMef " +
"AND SUBSTRING(mef.code, 10 - LENGTH(nomenMef.finCodeMef10Car) + 1, LENGTH(nomenMef.finCodeMef10Car)) = nomenMef.finCodeMef10Car " +
"OR " +
"SUBSTRING(mef.mefRattachement, 1, LENGTH(nomenMef.debutCodeMef)) = nomenMef.debutCodeMef " +
"AND SUBSTRING(mef.mefRattachement, 10 - LENGTH(nomenMef.finCodeMef10Car) + 1, LENGTH(nomenMef.finCodeMef10Car)) = nomenMef.finCodeMef10Car " +
") " +
"AND mef.mefSelectionne = TRUE " +
"AND nomenMef.codeTs = :codeTs " +
"AND (mef.dateFermeture > CURRENT_DATE OR mef.dateFermeture IS NULL) " +
"AND (ban.dateFermeture > CURRENT_DATE OR ban.dateFermeture IS NULL)")
List<EtabUaj> findEtabsByCodeTi(@Param("codeTs") String codeTs);⚠️ 关键注意事项:
-
避免逗号分隔混用隐式/显式 JOIN:Hibernate 6 更倾向统一使用
JOIN ... ON显式语法,而非混合,(隐式笛卡尔积)与JOIN。建议将TiMefAccueil nomenMef也改为JOIN TiMefAccueil nomenMef(若存在关联映射)或确认其是否需真正 JOIN(否则可考虑子查询或IN替代); -
IS NULL替代= null:JPQL 中判空必须用IS NULL,原mef.mefRattachement = null已修正; -
函数大小写兼容性:
SUBSTRING,LENGTH,CURRENT_DATE等为标准 JPQL 函数,Hibernate 6 默认支持,但若底层数据库方言不兼容,可启用hibernate.dialect.resolver或自定义方言; -
性能提示:该查询含多层嵌套字符串匹配(
SUBSTRING+LENGTH),建议在数据库侧为mef.code、mef.mefRattachement及nomenMef.*字段建立组合索引,或考虑预计算匹配字段。
总结:Hibernate 6 的 JPQL 解析器强化了“JOIN 作用域隔离”,本质是提升查询语义安全性。迁移时需重审所有 JOIN ... ON 的左侧实体归属,并按数据依赖关系线性组织 JOIN 顺序——这不仅解决报错,也使查询逻辑更清晰、更易维护。

















