Dengan model domain berikut, saya ingin memuat semua Answer
s termasuk Value
s dan sub-anak mereka masing-masing dan memasukkannya AnswerDTO
ke dalam kemudian dikonversi ke JSON. Saya memiliki solusi yang berfungsi tetapi mengalami masalah N +1 yang ingin saya singkirkan dengan menggunakan ad-hoc @EntityGraph
. Semua asosiasi dikonfigurasikan LAZY
.
@Query("SELECT a FROM Answer a")
@EntityGraph(attributePaths = {"value"})
public List<Answer> findAll();
Menggunakan ad-hoc @EntityGraph
pada Repository
metode ini saya dapat memastikan bahwa nilai-nilai sudah diambil sebelumnya untuk mencegah N + 1 pada Answer->Value
asosiasi. Sementara hasil saya baik-baik saja ada masalah N +1, karena malas memuat selected
asosiasi dari MCValue
s.
Menggunakan ini
@EntityGraph(attributePaths = {"value.selected"})
gagal, karena selected
bidang ini tentu saja hanya sebagian dari beberapa Value
entitas:
Unable to locate Attribute with the the given name [selected] on this ManagedType [x.model.Value];
Bagaimana saya bisa memberi tahu JPA hanya mencoba mengambil selected
asosiasi jika nilainya adalah a MCValue
? Saya butuh sesuatu seperti optionalAttributePaths
.
sumber
selected
jawaban yang memiliki aMCValue
. Saya tidak suka bahwa ini akan memerlukan loop tambahan dan saya perlu mengelola pemetaan antara set data. Saya suka ide Anda untuk mengeksploitasi cache Hibernate untuk ini. Bisakah Anda menguraikan seberapa aman (dalam hal konsistensi) itu bergantung pada cache untuk mengandung hasil? Apakah ini berfungsi ketika kueri dibuat dalam transaksi? Saya takut sulit dikenali dan kesalahan inisialisasi malas sporadis.MCValue
entitas. Dan Anda tidak perlu loop tambahan. Anda harus mengambil semuaMCValue
entitas dengan 1 kueri yang bergabung keAnswer
dan menggunakan klausa WHERE yang sama dengan kueri Anda saat ini. Saya juga membicarakan hal ini dalam siaran langsung hari ini: youtu.be/70B9znTmi00?t=238 Ini dimulai pada 3:58 tetapi saya mengambil beberapa pertanyaan lain di antaranya ...SINGLE_TABLE_INHERITANCE
.Saya tidak tahu apa yang dilakukan Spring-Data di sana, tetapi untuk melakukan itu, Anda biasanya harus menggunakan
TREAT
operator untuk dapat mengakses sub-asosiasi tetapi implementasi untuk Operator itu cukup bermasalah. Hibernate mendukung akses properti subtipe implisit yang Anda perlukan di sini, tetapi tampaknya Spring-Data tidak dapat menangani ini dengan benar. Saya dapat merekomendasikan agar Anda melihat Blaze-Persistence Entity-Views , perpustakaan yang berfungsi di atas JPA yang memungkinkan Anda memetakan struktur yang sewenang-wenang terhadap model entitas Anda. Anda dapat memetakan model DTO Anda dengan cara yang aman, juga struktur warisan. Tampilan entitas untuk use case Anda bisa terlihat seperti iniDengan integrasi data pegas yang disediakan oleh Blaze-Persistence Anda dapat menentukan repositori seperti ini dan langsung menggunakan hasilnya
Ini akan menghasilkan kueri HQL yang memilih apa yang Anda petakan yang
AnswerDTO
mana adalah sesuatu seperti berikut ini.sumber
interface MCValueDTO extends ValueDTO { @Mapping("selected.id") Set<Long> getOption(); }
Proyek terbaru saya menggunakan GraphQL (yang pertama untuk saya) dan kami memiliki masalah besar dengan N + 1 kueri dan mencoba untuk mengoptimalkan kueri untuk hanya bergabung dengan tabel ketika mereka diperlukan. Saya telah menemukan Cosium / spring-data-jpa-entitas-graph tak tergantikan. Itu memperluas
JpaRepository
dan menambahkan metode untuk meneruskan dalam grafik entitas ke kueri. Anda kemudian dapat membuat grafik entitas dinamis saat runtime untuk menambahkan gabungan kiri hanya untuk data yang Anda butuhkan.Alur data kami terlihat seperti ini:
Untuk mengatasi masalah tidak termasuk node yang tidak valid ke dalam grafik entitas (misalnya
__typename
dari graphql), saya membuat kelas utilitas yang menangani pembuatan grafik entitas. Kelas panggilan lewat dalam nama kelas yang menghasilkan grafik, yang kemudian memvalidasi setiap node dalam grafik terhadap metamodel yang dikelola oleh ORM. Jika simpul tidak ada dalam model, simpul itu akan dihapus dari daftar simpul grafik. (Pemeriksaan ini perlu rekursif dan periksa setiap anak juga)Sebelum menemukan ini, saya telah mencoba proyeksi dan setiap alternatif lain yang direkomendasikan dalam dokumen Spring JPA / Hibernate, tetapi sepertinya tidak ada yang menyelesaikan masalah dengan elegan atau setidaknya dengan satu ton kode tambahan
sumber
selected
asosiasi tidak tersedia untuk semua jenis subvalue
.Diedit setelah komentar Anda:
Saya minta maaf, saya belum memahami masalah Anda di babak pertama, masalah Anda muncul saat startup pegas-data, tidak hanya ketika Anda mencoba memanggil findAll ().
Jadi, Anda sekarang dapat menavigasi contoh lengkap dapat menarik dari github saya: https://github.com/bdzzaid/stackoverflow-java/blob/master/jpa-hibernate/
Anda dapat dengan mudah mereproduksi dan memperbaiki masalah Anda di dalam proyek ini.
Secara efektif, data Pegas dan hibernasi tidak dapat menentukan grafik "terpilih" secara default dan Anda perlu menentukan cara untuk mengumpulkan opsi yang dipilih.
Jadi pertama-tama, Anda harus mendeklarasikan NamedEntityGraphs dari Jawaban kelas
Seperti yang Anda lihat, ada dua NamedEntityGraph untuk atribut nilai dari kelas Jawaban
Yang pertama untuk semua Nilai tanpa hubungan khusus untuk dimuat
Yang kedua untuk nilai Multichoice tertentu . Jika Anda menghapus yang ini, Anda mereproduksi pengecualian.
Kedua, Anda harus berada dalam konteks transaksional answerRepository.findAll () jika Anda ingin mengambil data dalam tipe LAZY
sumber
value
-association dariAnswer
tapi mendapatkanselected
asosiasi dalam kasus inivalue
adalahMCValue
. Jawaban Anda tidak termasuk informasi mengenai itu.OneToMany
sebagaiFetchType.EAGER
tetapi sebagaimana dinyatakan dalam pertanyaan: semua asosiasi adalahLAZY
.selected
untuk setiap jawaban alih-alih memuatnya di muka.