JPQLクエリのソリューション
これは、JPA仕様内のJPQLクエリでサポートされています。
ステップ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();
}
重要な注意事項
- 必ず、パッケージ名を含むBeanクラスへの完全修飾パスを指定してください。たとえば、Beanクラスが呼び出され
MyBean
、それがパッケージ内にある場合、Bean com.path.to
への完全修飾パスはになりますcom.path.to.MyBean
。単に提供MyBean
するだけでは機能しません(Beanクラスがデフォルトパッケージに含まれている場合を除きます)。
- 必ず、
new
キーワードを使用してBeanクラスコンストラクターを呼び出してください。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標準。
このような状況では、Beanクラスを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();
}
SQL AS
キーワードを使用して、結果フィールドをプロジェクションプロパティにマッピングし、明確なマッピングを行います。
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..........