Saltar al contenido

Cómo devolver un objeto personalizado de una consulta Spring Data JPA GROUP BY

Nuestros investigadores estrellas agotaron sus provisiones de café, en su búsqueda día y noche por la respuesta, hasta que Liliana encontró la contestación en Bitbucket y hoy la comparte aquí.

Solución:

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 
    @Query("SELECT " +
           "    new com.path.to.SurveyAnswerStatistics(v.answer, COUNT(v)) " +
           "FROM " +
           "    Survey v " +
           "GROUP BY " +
           "    v.answer")
    List findSurveyCount();

Notas importantes

  1. Asegúrese de proporcionar la ruta completa a la clase de bean, incluido el nombre del paquete. Por ejemplo, si la clase de bean se llama MyBean y esta en paquete com.path.tola ruta completamente calificada al bean será com.path.to.MyBean. Simplemente proporcionando MyBean no funcionará (a menos que la clase de bean esté en el paquete predeterminado).
  2. Asegúrese de llamar al constructor de clases de bean usando el new palabra clave. SELECT new com.path.to.MyBean(...) funcionará, mientras que SELECT com.path.to.MyBean(...) no.
  3. Asegúrate de pasar attributes exactamente en el mismo orden que el esperado en el constructor del bean. intentando pasar attributes en un orden diferente dará lugar a una excepción.
  4. Asegúrese de que la consulta sea una consulta JPA válida, es decir, no sea una consulta nativa. @Query("SELECT ...")o @Query(value = "SELECT ...")o @Query(value = "SELECT ...", nativeQuery = false) funcionará, mientras que @Query(value = "SELECT ...", nativeQuery = true) no trabajará. Esto se debe a que las consultas nativas se pasan sin modificaciones al proveedor de JPA y se ejecutan en el RDBMS subyacente como tal. Ya que new y com.path.to.MyBean no son palabras clave de SQL válidas, el RDBMS genera una excepción.

Solución para consultas nativas

Como se señaló anteriormente, el new ... La 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, el new ... la sintaxis no funcionará ya que la consulta se pasa directamente al RDBMS subyacente, que no comprende el new palabra clave ya que no es parte del estándar SQL.

En situaciones como estas, las clases de beans deben reemplazarse con interfaces Spring Data Projection.

Paso 1: Declarar una interfaz de proyección

package com.path.to;

public interface SurveyAnswerStatistics 
  String getAnswer();

  int getCnt();

Paso 2: Devuelve las propiedades proyectadas de la consulta

public interface SurveyRepository extends CrudRepository 
    @Query(nativeQuery = true, value =
           "SELECT " +
           "    v.answer AS answer, COUNT(v) AS cnt " +
           "FROM " +
           "    Survey v " +
           "GROUP BY " +
           "    v.answer")
    List findSurveyCount();

Usa el Sql AS palabra clave para asignar campos de resultados a propiedades de proyección para un mapeo inequívoco.

Esta lista de retorno de consulta SQL< Object[] > haría.

Puedes hacerlo de esta manera:

 @RestController
 @RequestMapping("/survey")
 public class SurveyController 

   @Autowired
   private SurveyRepository surveyRepository;

     @RequestMapping(value = "/find", method =  RequestMethod.GET)
     public Map findSurvey()
       List result = surveyRepository.findSurveyCount();
       Map map = null;
       if(result != null && !result.isEmpty())
          map = new HashMap();
          for (Object[] object : result) 
            map.put(((Long)object[0]),object[1]);
          
       
     return map;
     
 

Sé que esta es una pregunta antigua y ya ha sido respondida, pero aquí hay otro enfoque:

@Query("select new map(count(v) as cnt, v.answer) from Survey v group by v.answer")
public List findSurveyCount();

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *