在准备一个 JPA 的内容培训,在写多表联查时遇到一个小问题,记录一下。

现在有 3 张表,分别是学生表 Student, 科目表 Subject 和成绩表 Transcript, 成绩 Transcript 通过 subjectId 和 studentId 关联 Student 和 Subject 。代码如下:

1
2
3
4
@Query(value = " select new TranscriptVO(t,st,s) from TranscriptBean t " //
+ " left join SubjectBean s on t.subjectId = s.id " //
+ " left join StudentBean st on t.studentId = st.id") //
List<TranscriptVO> findAllTranscriptVO();

完成以上接口后测试,启动报错,报错内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class [TranscriptVO] [ select new TranscriptVO(t,st,s) from com.liulonglong.practice.bean.TranscriptBean t  left join com.liulonglong.practice.bean.SubjectBean s on t.subjectId = s.id  left join com.liulonglong.practice.bean.StudentBean st on t.studentId = st.id]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:138)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:713)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350)
at com.sun.proxy.$Proxy93.createQuery(Unknown Source)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:87)
... 82 common frames omitted

这个问题咱见过,小 Case, 是TranscriptVO的构造函数和 HQL 中对应不上,检查修改一下即可。检查 TranscriptVO 的构造函数是正确的,如下:

1
2
3
4
5
6
public TranscriptVO(TranscriptBean transcript, StudentBean student, SubjectBean subject) {
super();
this.transcript = transcript;
this.subject = subject;
this.student = student;
}

诶?啥情况!
再仔细看看报错信息,第一行中记录了 HQL 在执行时有做转换, 查询的 3 个 Bean 前都加上了包名,但 TranscriptVO 前没有包名,问题应该就在这里,修改 HQL 如下:

1
2
3
4
@Query(value = " select new com.liulonglong.practice.vo.TranscriptVO(t,st,s) from TranscriptBean t " //
+ " left join SubjectBean s on t.subjectId = s.id " //
+ " left join StudentBean st on t.studentId = st.id") //
List<TranscriptVO> findAllTranscriptVO();

问题解决。

Happy & Done