Solution pour les requêtes JPQL
Ceci est pris en charge pour les requêtes JPQL dans la spécification JPA .
Étape 1 : Déclarez une classe de bean simple
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;
}
}
Étape 2 : renvoyer les instances de bean à partir de la méthode du référentiel
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();
}
Notes IMPORTANTES
- Assurez-vous de fournir le chemin d'accès complet à la classe du bean, y compris le nom du package. Par exemple, si la classe du bean est appelée
MyBean
et qu'elle est dans le package com.path.to
, le chemin d'accès complet au bean sera com.path.to.MyBean
. Le simple fait de fournir MyBean
ne fonctionnera pas (sauf si la classe du bean est dans le package par défaut).
- Assurez-vous d'appeler le constructeur de classe bean en utilisant le
new
mot - clé. SELECT new com.path.to.MyBean(...)
fonctionnera, alors que SELECT com.path.to.MyBean(...)
non.
- Assurez-vous de passer les attributs exactement dans le même ordre que celui attendu dans le constructeur du bean. Tenter de transmettre les attributs dans un ordre différent entraînera une exception.
- Assurez-vous que la requête est une requête JPA valide, c'est-à-dire qu'il ne s'agit pas d'une requête native.
@Query("SELECT ...")
, ou @Query(value = "SELECT ...")
, ou @Query(value = "SELECT ...", nativeQuery = false)
fonctionnera, alors que @Query(value = "SELECT ...", nativeQuery = true)
ne fonctionnera pas. Cela est dû au fait que les requêtes natives sont transmises sans modifications au fournisseur JPA et sont exécutées sur le SGBDR sous-jacent en tant que tel. Puisque new
et com.path.to.MyBean
ne sont pas des mots clés SQL valides, le SGBDR lève alors une exception.
Solution pour les requêtes natives
Comme indiqué ci-dessus, la new ...
syntaxe est un mécanisme pris en charge par JPA et fonctionne avec tous les fournisseurs JPA. Cependant, si la requête elle-même n'est pas une requête JPA, c'est-à-dire une requête native, la new ...
syntaxe ne fonctionnera pas car la requête est transmise directement au SGBDR sous-jacent, qui ne comprend pas lenew
mot clé car il ne fait pas partie de la norme SQL.
Dans de telles situations, les classes de bean doivent être remplacées par des interfaces Spring Data Projection .
Étape 1 : déclarer une interface de projection
package com.path.to;
public interface SurveyAnswerStatistics {
String getAnswer();
int getCnt();
}
Étape 2 : renvoyer les propriétés projetées à partir de la requête
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();
}
Utilisez le AS
mot clé SQL pour mapper les champs de résultat aux propriétés de projection pour un mappage sans ambiguïté.
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..........