H2Dialect是否支持INNER JOIN <> ON <>语法?JUnit测试报错求助
QuerySyntaxException: Path expected for join!问题 我太懂这个坑了!你遇到的这个异常本质是Hibernate的H2方言(H2Dialect)对HQL的JOIN语法要求比你生产环境用的数据库(比如MySQL、PostgreSQL)要严格得多——它只支持基于实体关联路径的JOIN(比如INNER JOIN c.persona p这种写法),而不允许那种直接用ON子句关联无映射关系表的JOIN写法。
问题根源
你原来的命名查询应该是用了类似这样的非路径JOIN:
@NamedQuery(name = "MyEntity.getMyObject", query = "SELECT NEW MyObject(p.firstName, p.lastName, tp.other) " + "FROM MyEntity e " + "INNER JOIN Persona p ON p.id = e.personaId " + "INNER JOIN ThirdParty tp ON tp.personaId = p.id")
这种写法在生产数据库的HQL解析器里能跑,但H2的HQL解析器会直接抛出Path expected for join!,因为它要求JOIN必须基于实体类中定义的关联关系(比如@ManyToOne、@OneToMany注解的字段)。
两种修复方案
方案1:改用基于实体关联路径的JOIN(推荐)
如果你的实体类之间本来就有映射关联(比如MyEntity里有@ManyToOne private Persona persona;,Persona里有@OneToOne private ThirdParty thirdParty;),直接把查询改成路径式JOIN即可:
@NamedQuery(name = "MyEntity.getMyObject", query = "SELECT NEW MyObject(p.firstName, p.lastName, tp.other) " + "FROM MyEntity e " + "INNER JOIN e.persona p " + "INNER JOIN p.thirdParty tp")
这种写法既符合HQL的规范,又能在H2和生产数据库中正常运行。
方案2:改用原生SQL查询
如果你的实体之间没有定义关联关系,必须用ON子句来关联,那可以把命名查询改成原生SQL查询(用@NamedNativeQuery),绕过HQL的语法检查:
@NamedNativeQuery( name = "MyEntity.getMyObject", query = "SELECT p.first_name, p.last_name, tp.other " + "FROM my_entity e " + "INNER JOIN persona p ON p.id = e.persona_id " + "INNER JOIN third_party tp ON tp.persona_id = p.id", resultClass = MyObject.class )
注意原生SQL要使用数据库的实际表名和列名(不是实体类的字段名),如果MyObject是DTO,要确保字段顺序和查询结果列顺序一致。
额外提示
如果你的生产环境和测试环境用的方言不同,也可以考虑在测试时调整Hibernate的配置,比如开启一些宽松的语法兼容参数,但最稳妥的还是统一HQL的写法,让它能在所有环境下正常运行。
内容的提问来源于stack exchange,提问作者Eric

