Solusi untuk kueri JPQL
Ini didukung untuk kueri JPQL dalam spesifikasi JPA .
Langkah 1 : Deklarasikan kelas kacang sederhana
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;
}
}
Langkah 2 : Kembalikan instance kacang dari metode repositori
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();
}
Catatan penting
- Pastikan untuk memberikan jalur yang sepenuhnya memenuhi syarat ke kelas kacang, termasuk nama paket. Misalnya, jika kelas kacang dipanggil
MyBean
dan berada dalam paket com.path.to
, jalur yang sepenuhnya memenuhi syarat ke kacang akan menjadi com.path.to.MyBean
. Hanya menyediakan MyBean
tidak akan berhasil (kecuali kelas kacang ada dalam paket default).
- Pastikan untuk memanggil konstruktor kelas kacang menggunakan
new
kata kunci. SELECT new com.path.to.MyBean(...)
akan bekerja, sedangkan SELECT com.path.to.MyBean(...)
tidak.
- Pastikan untuk meneruskan atribut dengan urutan yang persis sama seperti yang diharapkan dalam pembuat kacang. Mencoba meneruskan atribut dalam urutan yang berbeda akan menyebabkan pengecualian.
- Pastikan kueri tersebut adalah kueri JPA yang valid, yang bukan kueri asli.
@Query("SELECT ...")
, atau @Query(value = "SELECT ...")
, atau @Query(value = "SELECT ...", nativeQuery = false)
akan berhasil, sedangkan @Query(value = "SELECT ...", nativeQuery = true)
tidak akan berhasil. Ini karena kueri native diteruskan tanpa modifikasi ke penyedia JPA, dan dijalankan terhadap RDBMS yang mendasarinya. Karena new
dan com.path.to.MyBean
bukan kata kunci SQL yang valid, RDBMS kemudian melontarkan pengecualian.
Solusi untuk kueri asli
Seperti disebutkan di atas, new ...
sintaksis adalah mekanisme yang didukung JPA dan berfungsi dengan semua penyedia JPA. Namun, jika kueri itu sendiri bukan kueri JPA, yaitu kueri asli, new ...
sintaksis tidak akan berfungsi karena kueri diteruskan langsung ke RDBMS yang mendasari, yang tidak memahami new
kata kunci karena bukan bagian dari standar SQL.
Dalam situasi seperti ini, kelas kacang perlu diganti dengan antarmuka Proyeksi Data Musim Semi .
Langkah 1 : Deklarasikan antarmuka proyeksi
package com.path.to;
public interface SurveyAnswerStatistics {
String getAnswer();
int getCnt();
}
Langkah 2 : Kembalikan properti yang diproyeksikan dari kueri
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();
}
Gunakan AS
kata kunci SQL untuk memetakan kolom hasil ke properti proyeksi untuk pemetaan yang tidak ambigu.
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
dalam keluaran Anda. Saya menganggap Anda digantiSurveyAnswerStatistics
dengan kelas Anda sendiriSurveyAnswerReport
. Anda perlu menentukan nama kelas yang sepenuhnya memenuhi syarat.com.domain.dto.SurveyAnswerReport
.JpaRepository
? Apakah ada konfigurasi yang terlewat?Kueri SQL ini akan mengembalikan Daftar <Object []>.
Anda bisa melakukannya dengan cara ini:
sumber
Saya tahu ini adalah pertanyaan lama dan sudah dijawab, tetapi inilah pendekatan lain:
sumber
Menggunakan antarmuka Anda bisa mendapatkan kode yang lebih sederhana. Tidak perlu membuat dan memanggil konstruktor secara manual
Langkah 1 : Deklarasikan intefrace dengan field yang diperlukan:
Langkah 2 : Pilih kolom dengan nama yang sama dengan getter di antarmuka dan kembalikan intefrace dari metode repositori:
sumber
tentukan kelas pojo khusus, katakan sureveyQueryAnalytics dan simpan kueri yang mengembalikan nilai di kelas pojo khusus Anda
sumber
Saya tidak suka nama tipe java dalam string kueri dan menanganinya dengan konstruktor tertentu. Spring JPA secara implisit memanggil konstruktor dengan hasil kueri dalam parameter HashMap:
Kode membutuhkan Lombok untuk menyelesaikan @Getter
sumber
Saya baru saja memecahkan masalah ini:
@Query(value = "SELECT ...", nativeQuery = true
)) jadi saya sarankan untuk mendefinisikan DTO kustom menggunakan antarmuka.sumber
Saya menggunakan DTO (antarmuka) khusus untuk memetakan kueri asli ke - pendekatan yang paling fleksibel dan aman untuk refactoring.
Masalah yang saya hadapi dengan ini - yang mengejutkan, urutan bidang di antarmuka dan kolom dalam kueri penting. Saya membuatnya berfungsi dengan memesan getter antarmuka berdasarkan abjad dan kemudian mengurutkan kolom dalam kueri dengan cara yang sama.
sumber
Kode di atas berhasil untuk saya.
sumber