Penerangan masalah

Seperti yang kami katakan di atas, anotasi LazyCollectionOption.EXTRA mempunyai masalah - ia melakukan permintaan berasingan kepada pangkalan data untuk setiap objek. Kami perlu menjelaskan kepada Hibernate bahawa kami mahu ia memuatkan semua objek kanak-kanak untuk objek induk kami dengan segera.

Pembangun Hibernate telah menghasilkan penyelesaian kepada masalah ini, operator pengambilan sertai di HQL.

Contoh pertanyaan HQL:

select distinct task from Task t left join fetch t.employee order by t.deadline

Dalam pertanyaan ini, semuanya mudah dan kompleks pada masa yang sama. Mari kita cuba membinanya sekeping demi sekeping.

Pilihan 1

Kami mahu memuat turun semua objektugasan, diisih mengikut tarikh akhir. Begini rupa permintaan itu:

select task from Task t order by t.deadline

Sedangkan semuanya jelas. Tetapi padangpekerjakelas Tugasan akan mengandungi koleksi Pekerja beranotasi dengan anotasi EXTRA . Dan objek koleksi ini tidak akan dimuatkan.

Pilihan 2

Paksa Hibernate untuk memuatkan objek kanak-kanak untuk objektugasan.

select task from Task t join fetch t.employee order by t.deadline

Dengan bantuan, kami secara eksplisit mengikat entiti Tugas dan Pekerja dalam pertanyaan kami. Hibernate sudah mengetahui perkara ini kerana kami menggunakan anotasi @ManyToMany pada medan ini.

Tetapi kami memerlukan penyata gabungan untuk melengkapkannya dengan penyata ambil untuk mendapatkan penyata penyertaan . Beginilah cara kami memberitahu Hibernate bahawa objek dalam koleksi Task.employee perlu dimuatkan daripada pangkalan data apabila permintaan kami dilaksanakan.

Pilihan 3

Penyelesaian sebelumnya mempunyai beberapa pepijat. Pertama, selepas menggunakan join, SQL tidak akan mengembalikan objek kepada kamitugasan, yang tidak mempunyai objek yang dikaitkan dengannya dalam jadual Pekerja. Beginilah cara inner join berfungsi .

Jadi kita perlu menambah gabungan kita dengan pengendali kiri dan mengubahnya menjadi gabungan kiri . Contoh:

select task from Task t left join fetch t.employee order by t.deadline

Pilihan 4

Tetapi bukan itu sahaja. Jika dalam kod anda hubungan antara entiti adalah banyak-ke-mungkin, maka akan terdapat pendua dalam hasil pertanyaan. Objek yang samatugasanboleh didapati pada pekerja yang berbeza (Objek pekerja).

Oleh itu, anda perlu menambah kata kunci yang berbeza selepas perkataan pilih untuk menyingkirkan objek Tugas pendua.

select distinct task from Task t left join fetch t.employee order by t.deadline

Ini adalah bagaimana dalam 4 langkah kami mencapai permintaan yang kami mulakan. Nah, kod Java akan kelihatan agak dijangka:

String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
return query.list();

JOIN FETCH Had

Tiada sesiapa yang sempurna. JOIN FETCH kenyataan juga. Ia mempunyai beberapa batasan. Dan yang pertama menggunakan kaedah setMaxResults() dan setFirstResult() .

Untuk pernyataan JOIN FETCH, Hibernate kami akan menjana pertanyaan yang sangat kompleks di mana kami menggabungkan tiga jadual menjadi satu: pekerja, tugas dan pekerja_tugas. Sebenarnya, ini bukan permintaan untuk pekerja atau tugas, tetapi untuk semua pasangan tugas pekerja yang diketahui.

Dan SQL boleh menggunakan pernyataan LIMIT dan OFFSETnya pada pertanyaan tepat bagi pasangan tugas pekerja. Pada masa yang sama, ia jelas mengikuti dari pertanyaan HQL bahawa kami ingin mendapatkan tugasan dengan tepat (Task), dan jika kami mengagihkan semula parameter FirstResult dan MaxResult kami, maka mereka harus merujuk secara khusus kepada objek Tugas.

Jika anda menulis kod seperti ini:

String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
       	    query.setFirstResult(0);
        	   query.setMaxResults(1);
return query.list();

Kemudian Hibernate tidak akan dapat menukar FirstResult dan MaxResult dengan betul kepada parameter OFFSET dan LIMIT bagi pertanyaan SQL.

Sebaliknya, ia akan melakukan tiga perkara:

  • Pertanyaan SQL akan memilih secara amnya semua data daripada jadual dan mengembalikannya kepada Hibernate
  • Hibernate akan memilih rekod yang diperlukan dalam ingatannya dan mengembalikannya kepada anda
  • Hibernate akan mengeluarkan amaran

Amaran akan menjadi seperti ini:

WARN [org.hibernate.hql.internal.ast.QueryTranslatorImpl] HHH000104: 
firstResult/maxResults specified with collection fetch; applying in memory!