Решение для запросов JPQL
Это поддерживается для запросов JPQL в спецификации JPA .
Шаг 1. Объявите простой класс 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;
}
}
Шаг 2. Верните экземпляры bean-компонентов из метода репозитория
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();
}
Важные заметки
- Обязательно укажите полный путь к классу компонента, включая имя пакета. Например, если вызывается класс компонента,
MyBean
и он находится в пакете com.path.to
, полный путь к компоненту будет com.path.to.MyBean
. Простое предоставление MyBean
не будет работать (если класс компонента не находится в пакете по умолчанию).
- Обязательно вызовите конструктор класса компонента с помощью
new
ключевого слова. SELECT new com.path.to.MyBean(...)
будет работать, тогда как SELECT com.path.to.MyBean(...)
не будет.
- Убедитесь, что атрибуты передаются в том же порядке, что и в конструкторе bean-компонента. Попытка передать атрибуты в другом порядке приведет к исключению.
- Убедитесь, что запрос является допустимым запросом JPA, то есть это не собственный запрос.
@Query("SELECT ...")
, или @Query(value = "SELECT ...")
, или @Query(value = "SELECT ...", nativeQuery = false)
будет работать, тогда как @Query(value = "SELECT ...", nativeQuery = true)
работать не будет. Это связано с тем, что собственные запросы передаются провайдеру JPA без изменений и выполняются для базовой СУБД как таковой. Поскольку new
и com.path.to.MyBean
не являются допустимыми ключевыми словами SQL, СУБД генерирует исключение.
Решение для собственных запросов
Как отмечалось выше, new ...
синтаксис является механизмом, поддерживаемым JPA, и работает со всеми поставщиками JPA. Однако, если сам запрос не является запросом JPA, то есть это собственный запрос, new ...
синтаксис не будет работать, поскольку запрос передается непосредственно в базовую СУБД, которая не понимаетnew
ключевое слово, поскольку оно не является частью стандарт SQL.
В подобных ситуациях классы компонентов необходимо заменить интерфейсами Spring Data Projection .
Шаг 1. Объявите интерфейс проекции
package com.path.to;
public interface SurveyAnswerStatistics {
String getAnswer();
int getCnt();
}
Шаг 2. Верните прогнозируемые свойства из запроса
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();
}
Используйте AS
ключевое слово SQL для сопоставления полей результатов со свойствами проекции для однозначного сопоставления.
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
в вашем выводе. Я предполагаю, что вы заменилиSurveyAnswerStatistics
свой классSurveyAnswerReport
. Вам необходимо указать полное имя класса.com.domain.dto.SurveyAnswerReport
.JpaRepository
? Я пропустил какую-то конфигурацию?Этот SQL-запрос возвращает List <Object []>.
Сделать это можно так:
источник
Я знаю, что это старый вопрос, и на него уже был дан ответ, но вот другой подход:
источник
Используя интерфейсы, вы можете получить более простой код. Нет необходимости создавать и вызывать конструкторы вручную
Шаг 1. Объявите intefrace с обязательными полями:
Шаг 2 : Выберите столбцы с тем же именем, что и геттер в интерфейсе, и верните intefrace из метода репозитория:
источник
определите настраиваемый класс pojo, скажем sureveyQueryAnalytics, и сохраните возвращаемое значение запроса в своем настраиваемом классе pojo
источник
Мне не нравятся имена типов java в строках запроса, и я обрабатываю их с помощью определенного конструктора. Spring JPA неявно вызывает конструктор с результатом запроса в параметре HashMap:
Коду нужен Lombok для разрешения @Getter
источник
Я только что решил эту проблему:
@Query(value = "SELECT ...", nativeQuery = true
)), поэтому я рекомендую определять собственный DTO с помощью интерфейса.источник
Я использовал настраиваемый DTO (интерфейс) для сопоставления собственного запроса - наиболее гибкий подход и безопасный для рефакторинга.
Проблема, с которой я столкнулся, - это удивительно, что порядок полей в интерфейсе и столбцов в запросе имеет значение. Я заставил его работать, упорядочив геттеры интерфейса в алфавитном порядке, а затем таким же образом упорядочив столбцы в запросе.
источник
Приведенный выше код работал у меня.
источник