Solução para consultas JPQL
Isso é suportado para consultas JPQL na especificação JPA .
Etapa 1 : declarar uma classe de bean simples
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;
}
}
Etapa 2 : retornar instâncias de bean do método de repositório
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();
}
Anotações importantes
- Certifique-se de fornecer o caminho totalmente qualificado para a classe do bean, incluindo o nome do pacote. Por exemplo, se a classe do bean for chamada
MyBean
e estiver no pacote com.path.to
, o caminho totalmente qualificado para o bean será com.path.to.MyBean
. Simplesmente fornecer MyBean
não funcionará (a menos que a classe do bean esteja no pacote padrão).
- Certifique-se de chamar o construtor da classe do bean usando a
new
palavra - chave. SELECT new com.path.to.MyBean(...)
vai funcionar, SELECT com.path.to.MyBean(...)
mas não.
- Certifique-se de passar os atributos exatamente na mesma ordem esperada no construtor do bean. Tentar passar atributos em uma ordem diferente levará a uma exceção.
- Certifique-se de que a consulta seja uma consulta JPA válida, ou seja, não é uma consulta nativa.
@Query("SELECT ...")
, ou @Query(value = "SELECT ...")
, ou @Query(value = "SELECT ...", nativeQuery = false)
funcionará, enquanto @Query(value = "SELECT ...", nativeQuery = true)
não funcionará. Isso ocorre porque as consultas nativas são passadas sem modificações para o provedor JPA e são executadas no RDBMS subjacente como tal. Como new
e com.path.to.MyBean
não são palavras-chave SQL válidas, o RDBMS lança uma exceção.
Solução para consultas nativas
Conforme observado acima, a new ...
sintaxe é um mecanismo suportado por JPA e funciona com todos os provedores JPA. No entanto, se a consulta em si não for uma consulta JPA, ou seja, é uma consulta nativa, a new ...
sintaxe não funcionará, pois a consulta é passada diretamente para o RDBMS subjacente, que não entende a new
palavra-chave, pois não faz parte de o padrão SQL.
Em situações como essas, as classes de bean precisam ser substituídas por interfaces Spring Data Projection .
Etapa 1 : declarar uma interface de projeção
package com.path.to;
public interface SurveyAnswerStatistics {
String getAnswer();
int getCnt();
}
Etapa 2 : Retorne as propriedades projetadas da 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();
}
Use a AS
palavra-chave SQL para mapear campos de resultado para propriedades de projeção para mapeamento 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..........
SurveyAnswerReport
em sua saída. Presumo que você substituiuSurveyAnswerStatistics
por sua própria classeSurveyAnswerReport
. Você precisa especificar o nome da classe totalmente qualificado.com.domain.dto.SurveyAnswerReport
.JpaRepository
? Esqueci alguma configuração?Esta consulta SQL retorna List <Object []>.
Você pode fazer desta forma:
fonte
Eu sei que esta é uma pergunta antiga e já foi respondida, mas aqui está outra abordagem:
fonte
Usando interfaces, você pode obter um código mais simples. Não há necessidade de criar e chamar construtores manualmente
Etapa 1 : Declare a integração com os campos obrigatórios:
Etapa 2 : Selecione colunas com o mesmo nome de getter na interface e retorne a intefrace do método de repositório:
fonte
definir uma classe Pojo customizada, digamos sureveyQueryAnalytics, e armazenar o valor retornado da consulta em sua classe Pojo customizada
fonte
Não gosto de nomes de tipo java em strings de consulta e manuseio-os com um construtor específico. O Spring JPA chama implicitamente o construtor com o resultado da consulta no parâmetro HashMap:
O código precisa do Lombok para resolver @Getter
fonte
Acabei de resolver este problema:
@Query(value = "SELECT ...", nativeQuery = true
)) então eu recomendo definir DTO personalizado usando interface.fonte
Usei DTO (interface) customizado para mapear uma consulta nativa - a abordagem mais flexível e segura para refatoração.
O problema que tive com isso - que, surpreendentemente, a ordem dos campos na interface e as colunas na consulta são importantes. Eu fiz isso funcionar ordenando os getters de interface em ordem alfabética e, em seguida, ordenando as colunas na consulta da mesma maneira.
fonte
O código acima funcionou para mim.
fonte