Solución para consultas JPQL
Esto es compatible con consultas JPQL dentro de la especificación JPA .
Paso 1 : declarar una clase de frijol 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;
}
}
Paso 2 : devolver instancias de bean desde el método de repositorio
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();
}
Notas importantes
- Asegúrese de proporcionar la ruta completa a la clase de bean, incluido el nombre del paquete. Por ejemplo, si se llama a la clase de bean
MyBean
y está en el paquete com.path.to
, la ruta completa al bean será com.path.to.MyBean
. Simplemente proporcionar MyBean
no funcionará (a menos que la clase de bean esté en el paquete predeterminado).
- Asegúrese de llamar al constructor de la clase bean usando la
new
palabra clave. SELECT new com.path.to.MyBean(...)
funcionará, mientras SELECT com.path.to.MyBean(...)
que no.
- Asegúrese de pasar los atributos exactamente en el mismo orden que el esperado en el constructor del bean. Si intenta pasar atributos en un orden diferente, se producirá una excepción.
- Asegúrese de que la consulta sea una consulta JPA válida, es decir, que no sea una consulta nativa.
@Query("SELECT ...")
O @Query(value = "SELECT ...")
, o @Query(value = "SELECT ...", nativeQuery = false)
va a trabajar, mientras que @Query(value = "SELECT ...", nativeQuery = true)
no va a funcionar. Esto se debe a que las consultas nativas se pasan sin modificaciones al proveedor JPA y se ejecutan contra el RDBMS subyacente como tal. Dado que new
y com.path.to.MyBean
no son palabras clave SQL válidas, RDBMS lanza una excepción.
Solución para consultas nativas
Como se señaló anteriormente, la new ...
sintaxis es un mecanismo compatible con JPA y funciona con todos los proveedores de JPA. Sin embargo, si la consulta en sí no es una consulta JPA, es decir, es una consulta nativa, la new ...
sintaxis no funcionará ya que la consulta se pasa directamente al RDBMS subyacente, que no comprende la new
palabra clave ya que no es parte de el estándar SQL.
En situaciones como estas, las clases de bean deben reemplazarse con interfaces Spring Data Projection .
Paso 1 : declare una interfaz de proyección
package com.path.to;
public interface SurveyAnswerStatistics {
String getAnswer();
int getCnt();
}
Paso 2 : devolver las propiedades proyectadas de la consulta
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();
}
Utilice la AS
palabra clave SQL para asignar campos de resultados a propiedades de proyección para un mapeo inequívoco.
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..........