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;
}
}
第二步:从存储库方法返回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();
}
第二步:从查询中返回预测属性。
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..........
- Pranav C Balancom.domain.dto.SurveyAnswerReport
。 - manishJpaRepository
返回自定义类型时,出现了java.lang.IllegalArgumentException: PersistentEntity must not be null!
的错误提示。这是我漏掉了某些配置吗? - marioosh