Soluzione per query JPQL
Questo è supportato per le query JPQL all'interno della specifica JPA .
Passaggio 1 : dichiarare una semplice classe di 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;
}
}
Passaggio 2 : restituire le istanze del bean dal metodo del repository
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();
}
Note importanti
- Assicurati di fornire il percorso completo alla classe bean, incluso il nome del pacchetto. Ad esempio, se la classe bean viene chiamata
MyBean
ed è nel pacchetto com.path.to
, il percorso completo del bean sarà com.path.to.MyBean
. La semplice fornitura MyBean
non funzionerà (a meno che la classe bean non sia nel pacchetto predefinito).
- Assicurati di chiamare il costruttore della classe bean usando la
new
parola chiave. SELECT new com.path.to.MyBean(...)
funzionerà, mentre SELECT com.path.to.MyBean(...)
no.
- Assicurati di passare gli attributi esattamente nello stesso ordine di quello previsto nel costruttore del bean. Il tentativo di passare attributi in un ordine diverso porterà a un'eccezione.
- Assicurati che la query sia una query JPA valida, ovvero non è una query nativa.
@Query("SELECT ...")
, o @Query(value = "SELECT ...")
, o @Query(value = "SELECT ...", nativeQuery = false)
funzionerà, mentre @Query(value = "SELECT ...", nativeQuery = true)
non funzionerà. Questo perché le query native vengono passate senza modifiche al provider JPA e vengono eseguite sull'RDBMS sottostante in quanto tale. Poiché new
e com.path.to.MyBean
non sono parole chiave SQL valide, RDBMS genera un'eccezione.
Soluzione per query native
Come notato sopra, la new ...
sintassi è un meccanismo supportato da JPA e funziona con tutti i fornitori di JPA. Tuttavia, se la query stessa non è una query JPA, ovvero è una query nativa, la new ...
sintassi non funzionerà poiché la query viene passata direttamente all'RDBMS sottostante, che non comprende la new
parola chiave poiché non fa parte di lo standard SQL.
In situazioni come queste, le classi di bean devono essere sostituite con le interfacce Spring Data Projection .
Passaggio 1 : dichiarare un'interfaccia di proiezione
package com.path.to;
public interface SurveyAnswerStatistics {
String getAnswer();
int getCnt();
}
Passaggio 2 : restituire le proprietà proiettate dalla query
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();
}
Utilizzare la AS
parola chiave SQL per mappare i campi dei risultati alle proprietà di proiezione per una mappatura univoca.
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..........