JPQL查询解决方案
JPA规范中的 JPQL查询支持此功能。
步骤1:声明一个简单的bean类
package com.path.to;
public class SurveyAnswerStatistics {
private String answer;
private Long cnt;
public SurveyAnswerStatistics(String answer, Long cnt) {
this.answer = answer;
this.count = cnt;
}
}
步骤2:从存储库方法返回bean实例
public interface SurveyRepository extends CrudRepository<Survey, Long> {
@Query("SELECT " +
" new com.path.to.SurveyAnswerStatistics(v.answer, COUNT(v)) " +
"FROM " +
" Survey v " +
"GROUP BY " +
" v.answer")
List<SurveyAnswerStatistics> findSurveyCount();
}
重要笔记
- 确保提供到bean类的标准路径,包括包名。例如,如果bean类被调用
MyBean
并且在包中com.path.to
,则指向bean的标准路径将为com.path.to.MyBean
。仅提供MyBean
将不起作用(除非bean类在默认程序包中)。
- 确保使用
new
关键字调用bean类的构造函数。SELECT new com.path.to.MyBean(...)
会工作,而SELECT com.path.to.MyBean(...)
不会。
- 确保以与bean构造函数中期望的顺序完全相同的顺序传递属性。尝试以不同顺序传递属性将导致异常。
- 确保查询是有效的JPA查询,也就是说,它不是本机查询。
@Query("SELECT ...")
,或@Query(value = "SELECT ...")
,或@Query(value = "SELECT ...", nativeQuery = false)
将起作用,而@Query(value = "SELECT ...", nativeQuery = true)
将不起作用。这是因为本机查询无需修改就传递给JPA提供程序,并照此针对基础RDBMS执行。由于new
和com.path.to.MyBean
是无效的SQL关键字,因此RDBMS会引发异常。
本机查询解决方案
如上所述,该new ...
语法是JPA支持的机制,并且可与所有JPA提供程序一起使用。但是,如果查询本身不是JPA查询,即它是本机查询,则new ...
语法将不起作用,因为该查询直接传递给基础RDBMS,该RDBMS不理解该new
关键字,因为它不是该关键字的一部分。 SQL标准。
在这种情况下,需要用Spring Data Projection接口替换bean类。
步骤1:声明投影界面
package com.path.to;
public interface SurveyAnswerStatistics {
String getAnswer();
int getCnt();
}
步骤2:从查询中返回投影的属性
public interface SurveyRepository extends CrudRepository<Survey, Long> {
@Query(nativeQuery = true, value =
"SELECT " +
" v.answer AS answer, COUNT(v) AS cnt " +
"FROM " +
" Survey v " +
"GROUP BY " +
" v.answer")
List<SurveyAnswerStatistics> findSurveyCount();
}
使用SQL AS
关键字将结果字段映射到投影属性,以进行明确的映射。
Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class [SurveyAnswerReport] [select new SurveyAnswerReport(v.answer,count(v.id)) from com.furniturepool.domain.Survey v group by v.answer] at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1750) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677) at org.hibernate.jpa.spi.AbstractEnti..........