Рішення для запитів JPQL
Це підтримується для запитів JPQL в специфікації JPA .
Крок 1 : Оголосіть простий клас квасолі
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 : Повернення екземплярів біна з методу сховища
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();
}
Важливі примітки
- Не забудьте вказати повністю кваліфікований шлях до класу бобів, включаючи назву пакета. Наприклад, якщо клас bean називається
MyBean
і він знаходиться в пакеті com.path.to
, буде повністю кваліфікований шлях до квасоліcom.path.to.MyBean
. Просто надання MyBean
не буде працювати (якщо тільки клас бобів не знаходиться в пакеті за замовчуванням).
- Обов’язково зателефонуйте конструктору класу bean за допомогою
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 і виконуються проти базових RDBMS як таких. Оскільки new
і com.path.to.MyBean
не є дійсними ключовими словами SQL, RDBMS викидає виняток.
Рішення для власних запитів
Як зазначалося вище, new ...
синтаксис є механізмом, підтримуваним JPA, і працює з усіма постачальниками JPA. Однак якщо сам запит не є запитом JPA, тобто це нативний запит, new ...
синтаксис не буде працювати, оскільки запит передається безпосередньо базовій RDBMS, яка не розуміє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..........