Tolong bantu saya untuk memahami di mana harus menggunakan GABUNG biasa dan di mana GABUNGAN GABUNG.
Sebagai contoh, jika kita memiliki dua pertanyaan ini
FROM Employee emp
JOIN emp.department dep
dan
FROM Employee emp
JOIN FETCH emp.department dep
Apakah ada perbedaan di antara mereka? Jika ya, mana yang harus digunakan kapan?
Jawaban:
Dalam dua kueri ini, Anda menggunakan GABUNG untuk meminta semua karyawan yang memiliki setidaknya satu departemen terkait.
Namun, perbedaannya adalah: dalam kueri pertama Anda hanya mengembalikan Pengusaha untuk Hibernate. Di kueri kedua, Anda mengembalikan Karyawan dan semua Departemen terkait.
Jadi, jika Anda menggunakan kueri kedua, Anda tidak perlu melakukan kueri baru untuk membuka basis data lagi untuk melihat Departemen masing-masing Karyawan.
Anda dapat menggunakan permintaan kedua ketika Anda yakin bahwa Anda akan membutuhkan Departemen dari setiap Karyawan. Jika Anda tidak membutuhkan Departemen, gunakan kueri pertama.
Saya sarankan membaca tautan ini jika Anda perlu menerapkan beberapa kondisi WHERE (apa yang mungkin Anda perlukan): Bagaimana cara mengekspresikan JPQL dengan benar "join fetch" dengan "where" klausa sebagai JPA 2 KriteriaQuery?
Memperbarui
Jika Anda tidak menggunakan
fetch
dan Departemen terus dikembalikan, karena pemetaan Anda antara Karyawan dan Departemen (a@OneToMany
) diselesaikan denganFetchType.EAGER
. Dalam hal ini, setiap permintaan HQL (denganfetch
atau tidak)FROM Employee
akan membawa semua Departemen. Ingat bahwa semua pemetaan * ToOne (@ManyToOne
dan@OneToOne
) adalah EAGER secara default.sumber
fetch
harus digunakan jika (menggunakan contoh kami) Anda ingin memesan oleh beberapa atribut Departemen. Kalau tidak, (paling tidak berlaku untuk PG) yang mungkin Anda dapatkanERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
di tautan ini yang saya sebutkan sebelumnya di komentar, baca bagian ini:
"JOIN FETCH" ini akan berpengaruh jika Anda memiliki (fetch = FetchType.LAZY) properti untuk koleksi di dalam entitas (contoh di bawah).
Dan itu hanya efek metode "ketika permintaan harus terjadi". Dan Anda juga harus tahu ini :
kapan asosiasi diambil -> tipe "FETCH" Anda
bagaimana cara mengambil -> Bergabung / pilih / Subselect / Batch
Dalam kasus Anda, FETCH hanya akan memiliki efek jika Anda memiliki departemen sebagai set di dalam Karyawan, sesuatu seperti ini di entitas:
ketika kamu menggunakan
Anda akan mendapatkan
emp
danemp.dep
. ketika Anda tidak menggunakan fetch Anda masih bisa mendapatkanemp.dep
tetapi hibernate akan memproses pilih lain ke database untuk mendapatkan set departemen itu.jadi itu hanya masalah penyempurnaan kinerja, tentang Anda ingin mendapatkan semua hasil (Anda membutuhkannya atau tidak) dalam satu permintaan (ingin mengambil), atau Anda ingin meminta yang terakhir ketika Anda membutuhkannya (lazy fetching).
Gunakan pengambilan penuh semangat ketika Anda perlu mendapatkan data kecil dengan satu pilih (satu permintaan besar). Atau gunakan lazy fetching untuk menanyakan apa yang Anda butuhkan belakangan (banyak permintaan lebih kecil).
gunakan ambil ketika:
tidak ada koleksi / set besar yang tidak dibutuhkan di dalam entitas yang akan Anda dapatkan
komunikasi dari server aplikasi ke server database terlalu jauh dan perlu waktu lama
Anda mungkin perlu bahwa koleksi terakhir ketika Anda tidak memiliki akses ke sana ( luar dari transaksional metode / kelas)
sumber
List
bukanSet
?FETCH
kata kunci dalam pernyataan JPQL menyiratkan properti yang diambil dengan penuh semangat?IKUTI
Saat menggunakan
JOIN
terhadap asosiasi entitas, JPA akan menghasilkan JOIN antara entitas induk dan tabel entitas anak dalam pernyataan SQL yang dihasilkan.Jadi, ambil contoh Anda, saat menjalankan permintaan JPQL ini:
Hibernate akan menghasilkan pernyataan SQL berikut:
BERGABUNG FETCH
Jadi, dibandingkan dengan
JOIN
,JOIN FETCH
memungkinkan Anda untuk memproyeksikan kolom tabel bergabung dalamSELECT
klausa pernyataan SQL yang dihasilkan.Jadi, dalam contoh Anda, saat menjalankan permintaan JPQL ini:
Hibernate akan menghasilkan pernyataan SQL berikut:
Juga,
JOIN FETCH
merupakan cara yang bagus untuk mengatasiLazyInitializationException
ketika menggunakan Hibernate karena Anda dapat menginisialisasi asosiasi entitas menggunakanFetchType.LAZY
strategi pengambilan bersama dengan entitas utama yang Anda ambil.sumber
Jika Anda memiliki
@oneToOne
pemetaan yang diatur keFetchType.LAZY
dan Anda menggunakan kueri kedua (karena Anda perlu objek Departemen untuk dimuat sebagai bagian dari objek Karyawan) yang akan dilakukan Hibernate, itu akan mengeluarkan pertanyaan untuk mengambil objek Departemen untuk setiap objek Karyawan individu yang diambilnya dari DB.Kemudian, dalam kode Anda dapat mengakses objek Departemen melalui asosiasi tunggal ke Karyawan dan Hibernate tidak akan mengeluarkan kueri apa pun untuk mengambil objek Departemen untuk Karyawan yang diberikan.
Ingat, Hibernate masih mengeluarkan kueri yang sama dengan jumlah Karyawan yang telah diambilnya. Hibernate akan mengeluarkan jumlah kueri yang sama di kedua kueri di atas, jika Anda ingin mengakses objek Departemen semua objek Karyawan
sumber
Dherik: Saya tidak yakin dengan apa yang Anda katakan, ketika Anda tidak menggunakan fetch hasilnya akan bertipe:
List<Object[ ]>
yang berarti daftar tabel Object dan bukan daftar Karyawan.Saat Anda menggunakan fetch, hanya ada satu pilih dan hasilnya adalah daftar Karyawan yang
List<Employee>
berisi daftar keberangkatan. Ini mengesampingkan deklarasi malas entitas.sumber
fetch
, permintaan Anda hanya akan mengembalikan Karyawan. Jika Departemen, bahkan dalam kasus ini, terus dikembalikan, adalah karena pemetaan Anda antara Karyawan dan Departemen (a @OneToMany) diselesaikan dengan FetchType.EAGER. Dalam hal ini, setiap permintaan HQL (denganfetch
atau tidak)FROM Employee
akan membawa semua Departemen.@OneToMany(fetch = FetchType.EAGER
). Jika tidak, Departemen tidak akan dikembalikan.select
dibuat di HQL. CobaSELECT emp FROM Employee emp JOIN FETCH emp.department dep
. JPA / Hibernate memiliki perilaku ini pengembalian suatuList
dariObject[]
ketika Anda ommitSELECT
bagian.