JPA两字段关联另一表同列时自定义HQL查询抛出异常如何解决?
异常触发原因
- 你的HQL写法存在语法映射歧义:自定义HQL中没有给
Book实体指定别名,所有选中字段都没有归属标识,当同时选中author、reviewer两个关联到同一Person实体的字段时,Hibernate的HQL解析器无法识别第二个同类型关联字段的类型映射规则,直接抛出No data type for node异常。仅保留author时不存在同类型字段歧义,所以可以正常解析,但此时返回的结果实际是Object[]数组,并非你预期的Book实体,后续直接作为Book操作仍会报错。 - 显式指定字段列表的HQL默认返回值类型为
List<Object[]>,你方法声明的返回值是List<Book>,没有配置映射规则的情况下本身就存在类型不匹配问题。Spring Data JPA自带的findAll()默认执行SELECT b FROM Book b语义,直接返回完整的Book实体实例,会自动映射所有字段包括关联属性,因此可以正常工作。
解决方案
给你两种常用的实现方案,按需选择:
方案1:直接查询完整Book实体(最推荐)
如果你的需求就是查询所有Book的完整属性,不需要做字段裁剪,直接简化HQL即可,不需要手动罗列字段,和findAll()语义完全一致:
@Query("SELECT b FROM Book b") List<Book> testQuery();
如果需要优化关联查询性能,避免N+1查询问题,可以加上JOIN FETCH一次性关联查询出author和reviewer:
@Query("SELECT b FROM Book b JOIN FETCH b.author JOIN FETCH b.reviewer") List<Book> testQuery();
方案2:显式指定字段+构造器映射
如果你确实需要裁剪查询字段,只查指定的四个属性,就用构造器表达式将结果映射为Book实体:
- 首先给Book类添加对应参数的构造方法:
// 注意全参构造如果已经存在可以省略,要保证参数顺序、类型和HQL中选中的字段一致 public Book(int id, String name, Person author, Person reviewer) { this.id = id; this.name = name; this.author = author; this.reviewer = reviewer; }
- 修改HQL用构造器封装查询结果,注意要写全Book类的全限定类名:
// 替换为你项目中Book类实际的全限定包名 @Query("SELECT new com.example.demo.entity.Book(b.id, b.name, b.author, b.reviewer) FROM Book b") List<Book> testQuery();
内容的提问来源于stack exchange,提问作者Дмитрий Тищенко
相关产品推荐
相关产品推荐

