Saya menggunakan JPA dalam proyek saya.
Saya sampai pada permintaan di mana saya perlu membuat operasi gabungan di lima tabel. Jadi saya membuat kueri asli yang mengembalikan lima bidang.
Sekarang saya ingin mengonversi objek hasil ke kelas java POJO yang berisi lima Strings yang sama.
Apakah ada cara di JPA untuk secara langsung melemparkan hasil itu ke daftar objek POJO ??
Saya datang ke solusi berikut ..
@NamedNativeQueries({
@NamedNativeQuery(
name = "nativeSQL",
query = "SELECT * FROM Actors",
resultClass = db.Actor.class),
@NamedNativeQuery(
name = "nativeSQL2",
query = "SELECT COUNT(*) FROM Actors",
resultClass = XXXXX) // <--------------- problem
})
Sekarang di sini di resultClass, apakah kita perlu menyediakan kelas yang merupakan entitas JPA yang sebenarnya? ATAU Kami dapat mengonversinya ke kelas JAVA POJO yang berisi nama kolom yang sama?
Jawaban:
JPA menyediakan suatu
SqlResultSetMapping
yang memungkinkan Anda untuk memetakan apa pun pengembalian dari permintaan asli Anda ke Entitasatau kelas khusus.EDIT JPA 1.0 tidak memungkinkan pemetaan untuk kelas non-entitas. Hanya di JPA 2.1 ConstructorResult telah ditambahkan untuk memetakan nilai pengembalian kelas java.
Juga, untuk masalah OP dengan penghitungan, itu harus cukup untuk mendefinisikan pemetaan set hasil dengan satu
ColumnResult
sumber
ConstructorResult
sebagai salah satu parameterSqlResultSetMapping
yang memungkinkan untuk menggunakan pojo dengan semua bidang yang ditetapkan dalam konstruktor. Saya akan memperbarui jawabannya.Saya telah menemukan beberapa solusi untuk ini.
Menggunakan Entitas yang Dipetakan (JPA 2.0)
Menggunakan JPA 2.0 tidak mungkin untuk memetakan permintaan asli ke POJO, itu hanya dapat dilakukan dengan suatu entitas.
Misalnya:
Tetapi dalam kasus ini
Jedi
,, harus kelas entitas yang dipetakan.Alternatif untuk menghindari peringatan yang tidak dicentang di sini, adalah dengan menggunakan kueri asli yang bernama. Jadi jika kita mendeklarasikan kueri asli dalam suatu entitas
Kemudian, kita cukup melakukan:
Ini lebih aman, tetapi kami masih dibatasi untuk menggunakan entitas yang dipetakan.
Pemetaan Manual
Sebuah solusi yang saya coba sedikit (sebelum kedatangan JPA 2.1) melakukan pemetaan terhadap konstruktor POJO menggunakan sedikit refleksi.
Metode ini pada dasarnya mengambil array tuple (seperti yang dikembalikan oleh query asli) dan memetakannya terhadap kelas POJO yang disediakan dengan mencari konstruktor yang memiliki jumlah bidang yang sama dan jenis yang sama.
Kemudian kita dapat menggunakan metode yang mudah digunakan seperti:
Dan kita cukup menggunakan teknik ini sebagai berikut:
JPA 2.1 dengan @SqlResultSetMapping
Dengan kedatangan JPA 2.1, kita dapat menggunakan anotasi @SqlResultSetMapping untuk menyelesaikan masalah.
Kita perlu mendeklarasikan pemetaan kumpulan hasil di suatu tempat di suatu entitas:
Dan kemudian kita lakukan:
Tentu saja, dalam hal ini
Jedi
tidak perlu menjadi entitas yang dipetakan. Ini bisa menjadi POJO biasa.Menggunakan Pemetaan XML
Saya adalah salah satu dari mereka yang menemukan menambahkan semua ini
@SqlResultSetMapping
cukup invasif di entitas saya, dan saya sangat tidak suka definisi nama query dalam entitas, jadi saya melakukan semua ini dalamMETA-INF/orm.xml
file:Dan itu semua solusi yang saya tahu. Dua yang terakhir adalah cara yang ideal jika kita dapat menggunakan JPA 2.1.
sumber
@SqlResultSetMapping
harus ditempatkan dalam suatu entitas karena dari situlah JPA akan membaca metadata dari. Anda tidak dapat mengharapkan JPA untuk memeriksa POJO Anda. Entitas tempat Anda meletakkan pemetaan tidak relevan, mungkin entitas yang lebih terkait dengan hasil POJO Anda. Sebagai alternatif, pemetaan dapat diekspresikan dalam XML untuk menghindari pemasangan dengan entitas yang sama sekali tidak terkait.@SqlResultSetMapping
itu mungkin perlu dicatat bahwaJedi
kelas akan membutuhkan konstruktor all-arg dan@ColumnResult
anotasi mungkin memerlukantype
atribut yang ditambahkan ke konversi yang mungkin tidak implisit (saya perlu menambahkantype = ZonedDateTime.class
beberapa kolom).Ya, dengan JPA 2.1 itu mudah. Anda memiliki Anotasi yang sangat berguna. Mereka menyederhanakan hidup Anda.
Pertama, nyatakan kueri asli Anda, lalu pemetaan set hasil Anda (yang menentukan pemetaan data yang dikembalikan oleh database ke POJO Anda). Tulis kelas POJO Anda untuk merujuk (tidak termasuk di sini untuk singkatnya). Last but not least: buat metode dalam DAO (misalnya) untuk memanggil kueri. Ini bekerja untuk saya di aplikasi dropwizard (1.0.0).
Pertama mendeklarasikan kueri asli dalam kelas entitas:
Di bawahnya Anda dapat menambahkan deklarasi pemetaan resultset:
Kemudian dalam DAO Anda bisa merujuk ke kueri sebagai
Itu dia.
sumber
Jika Anda menggunakan
Spring-jpa
, ini adalah suplemen untuk jawaban dan pertanyaan ini. Perbaiki ini jika ada kekurangan. Saya terutama menggunakan tiga metode untuk mencapai "hasil pemetaanObject[]
ke pojo" berdasarkan pada kebutuhan praktis yang saya penuhi:sql
dengan ituEntity
sudah cukup.2 mantan gagal, dan saya harus menggunakan a
nativeQuery
. Berikut ini contohnya. Pojo berharap:Metode 1 : Ubah pojo menjadi antarmuka:
Dan repositori:
Metode 2 : Gudang:
Catatan: urutan parameter konstruktor POJO harus identik dalam definisi POJO dan sql.
Metode 3 : Gunakan
@SqlResultSetMapping
dan@NamedNativeQuery
diEntity
sebagai contoh dalam jawaban Edwin Dalorzo ini.Dua metode pertama akan memanggil banyak penangan di tengah, seperti konverter kustom. Misalnya,
AntiStealing
tentukan asecretKey
, sebelum tetap ada, konverter dimasukkan untuk mengenkripsi itu. Ini akan menghasilkan 2 metode pertama mengembalikan kembali dikonversisecretKey
yang bukan yang saya inginkan. Sementara metode 3 akan mengatasi konverter, dan kembalisecretKey
akan sama dengan yang disimpan (yang terenkripsi).sumber
Prosedur unwrap dapat dilakukan untuk menetapkan hasil ke non-entitas (yaitu Kacang / POJO). Prosedurnya adalah sebagai berikut.
Penggunaan ini untuk implementasi JPA-Hibernate.
sumber
JobDTO
harus memiliki konstruktor default. Atau Anda dapat mengimplementasikan transformator Anda sendiri berdasarkanAliasToBeanResultTransformer
implementasi.Pertama, nyatakan penjelasan berikut:
Kemudian beri catatan POJO Anda sebagai berikut:
Kemudian tulis prosesor anotasi:
Gunakan kerangka kerja di atas sebagai berikut:
sumber
BeanUtils
?Cara termudah adalah dengan menggunakan proyeksi . Itu dapat memetakan hasil kueri langsung ke antarmuka dan lebih mudah diimplementasikan daripada menggunakan SqlResultSetMapping.
Contohnya ditunjukkan di bawah ini:
Bidang dari antarmuka yang diproyeksikan harus cocok dengan bidang di entitas ini. Kalau tidak, pemetaan lapangan mungkin rusak.
Juga jika Anda menggunakan
SELECT table.column
notasi selalu tentukan alias pencocokan nama dari entitas seperti yang ditunjukkan dalam contoh.sumber
Dalam hibernasi Anda dapat menggunakan kode ini untuk memetakan kueri asli Anda dengan mudah.
sumber
Menggunakan Hibernate:
sumber
Gaya lama menggunakan ResultSet
sumber
Karena orang lain telah menyebutkan semua solusi yang mungkin, saya membagikan solusi pemecahan masalah saya.
Dalam situasi saya dengan
Postgres 9.4
, saat bekerja denganJackson
,Saya yakin Anda dapat menemukan yang sama untuk database lain.
Juga hasil pencarian asli FYI, JPA 2.0 sebagai peta
sumber
Tidak yakin apakah ini cocok di sini, tetapi saya memiliki pertanyaan serupa dan menemukan solusi / contoh sederhana berikut untuk saya:
Dalam kasus saya, saya harus menggunakan bagian SQL yang didefinisikan dalam String di tempat lain, jadi saya tidak bisa hanya menggunakan NamedNativeQuery.
sumber
Gaya lama menggunakan Resultset
sumber
Kami telah menyelesaikan masalah menggunakan cara berikut:
sumber
Lihat contoh di bawah ini untuk menggunakan POJO sebagai entitas semu untuk mengambil hasil dari kueri asli tanpa menggunakan SqlResultSetMapping yang kompleks. Hanya perlu dua anotasi, @Enitas kosong dan @Id dummy di POJO Anda. @Id dapat digunakan pada bidang apa pun pilihan Anda, bidang @Id dapat memiliki kunci duplikat tetapi bukan nilai null.
Karena @Enity tidak memetakan ke tabel fisik apa pun, jadi POJO ini disebut entitas semu.
Lingkungan: eclipselink 2.5.0-RC1, jpa-2.1.0, mysql-connector-java-5.1.14
Anda dapat mengunduh proyek pakar lengkap di sini
Kueri asli didasarkan pada sampel karyawan mysql db http://dev.mysql.com/doc/employee/en/employees-installation.html
persistence.xml
Employee.java
EmployeeNativeQuery.java
sumber
list
, menurut dugaan, adalah daftarEmployee
, mengapa untuk setiap loop Anda mengulangi suatu tipeObject
? Jika Anda menulis untuk-setiap loopfor(Employee emp : list)
Anda maka Anda akan menemukan bahwa jawaban Anda salah dan isi daftar Anda bukan karyawan dan bahwa peringatan yang Anda tekan memiliki tujuan untuk mengingatkan Anda tentang kesalahan potensial ini.List<Employee> list = (List<Employee>) query.getResultList();
Perubahanfor (Object emp : list)
menjadifor (Employee emp : list)
lebih baik, tetapi tidak ada kesalahan jika disimpanObject emp
karena daftar adalah turunan dariList<Employee>
. Saya mengubah kode dalam proyek git tetapi tidak di sini untuk menjaga komentar Anda tetap relevan dengan posting asliQuery query = em.createNativeQuery("select * ...", Employee.class);
dan persistence.xml, kueri asli memang mengembalikan daftar Karyawan. Saya baru saja memeriksa dan menjalankan proyek tanpa masalah. Jika Anda mengatur sampel karyawan mysql db secara lokal, Anda harus dapat menjalankan proyek jugaEmployee
yang saya anggap sebagai entitas. Bukan?jika Anda menggunakan Spring, Anda bisa menggunakan
org.springframework.jdbc.core.RowMapper
Berikut ini sebuah contoh:
sumber
Menggunakan Hibernate:
sumber
Cara mudah untuk mengubah kueri SQL ke koleksi kelas POJO,
sumber
Yang Anda butuhkan hanyalah DTO dengan konstruktor:
dan menyebutnya:
sumber
Gunakan
DTO Design Pattern
. Itu digunakan diEJB 2.0
. Entitas dikelola wadah.DTO Design Pattern
digunakan untuk mengatasi masalah ini. Tapi, itu mungkin digunakan sekarang, ketika aplikasi dikembangkanServer Side
danClient Side
terpisah.DTO
digunakan ketikaServer side
tidak ingin meneruskan / kembaliEntity
dengan anotasi keClient Side
.Contoh DTO:
PersonEntity.java
PersonDTO.java
DTOBuilder.java
EntityBuilder.java <- itu memang perlu
sumber