Saya memiliki kelas Person:
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
@ManyToMany(fetch = FetchType.LAZY)
private List<Role> roles;
// etc
}
Dengan hubungan banyak ke banyak yang malas.
Di controller saya saya miliki
@Controller
@RequestMapping("/person")
public class PersonController {
@Autowired
PersonRepository personRepository;
@RequestMapping("/get")
public @ResponseBody Person getPerson() {
Person person = personRepository.findOne(1L);
return person;
}
}
Dan PersonRepository hanyalah kode ini, ditulis sesuai dengan panduan ini
public interface PersonRepository extends JpaRepository<Person, Long> {
}
Namun, dalam pengontrol ini saya benar-benar membutuhkan data-malas. Bagaimana saya bisa memicu pemuatannya?
Mencoba mengaksesnya akan gagal
gagal malas menginisialisasi kumpulan peran: no.dusken.momus.model.Person.roles, tidak dapat menginisialisasi proxy - tanpa Sesi
atau pengecualian lain tergantung pada apa yang saya coba.
Deskripsi-xml saya , jika diperlukan.
Terima kasih.
Person
objek yang diberikan beberapa parameter? Di dalamnyaQuery
, sertakanfetch
klausa dan muatRoles
juga untuk orang tersebut.Jawaban:
Anda harus membuat panggilan eksplisit pada koleksi malas untuk menginisialisasi (praktik umum adalah memanggil
.size()
untuk tujuan ini). Di Hibernate ada metode khusus untuk ini (Hibernate.initialize()
), tetapi JPA tidak memiliki yang setara dengan itu. Tentu saja Anda harus memastikan bahwa pemanggilan selesai, ketika sesi masih tersedia, jadi beri catatan metode pengontrol Anda@Transactional
. Alternatifnya adalah membuat lapisan Layanan antara antara Controller dan Repository yang dapat mengekspos metode yang menginisialisasi koleksi malas.Memperbarui:
Harap perhatikan bahwa solusi di atas mudah, tetapi menghasilkan dua pertanyaan berbeda pada basis data (satu untuk pengguna, satu lagi untuk perannya). Jika Anda ingin mencapai kinerja yang lebih baik, tambahkan metode berikut ke antarmuka repositori Spring Data JPA Anda:
Metode ini akan menggunakan klausa fetch join JPQL untuk memuat asosiasi peran dengan penuh semangat dalam satu perjalanan pulang-pergi ke basis data, dan karenanya akan mengurangi penalti kinerja yang ditimbulkan oleh dua kueri berbeda dalam solusi di atas.
sumber
join
tanpafetch
, set akan dikembalikan bersamainitialized = false
; Oleh karena itu masih mengeluarkan permintaan kedua setelah set diakses.fetch
adalah kunci untuk memastikan hubungan benar-benar dimuat dan menghindari permintaan kedua.Meskipun ini adalah pos lama, harap pertimbangkan untuk menggunakan @NamedEntityGraph (Javax Persistence) dan @EntityGraph (Spring Data JPA). Kombinasi tersebut berfungsi.
Contoh
dan kemudian repo musim semi seperti di bawah ini
sumber
@NamedEntityGraph
adalah bagian dari JPA 2.1 API, yang tidak diterapkan di Hibernate sebelum versi 4.3.0.@EntityGraph(attributePaths = "employeeGroups")
dapat digunakan secara langsung dalam Spring Data Repository untuk memberi anotasi metode tanpa perlu@NamedEntityGraph
pada @Entity Anda - kode lebih sedikit, mudah dimengerti ketika Anda membuka repo.Anda memiliki beberapa opsi
Lebih banyak pekerjaan, kinerja terbaik.
Lebih sedikit pekerjaan, biasanya dapat diterima di lingkungan web.
Lebih sedikit pekerjaan, berguna ketika OEMIV tidak pada pilihan, misalnya dalam aplikasi Swing, tetapi mungkin berguna juga pada implementasi repositori untuk menginisialisasi entitas apa pun dalam satu kesempatan.
Untuk opsi terakhir, saya menulis kelas utilitas, JpaUtils untuk memulai entitas di beberapa deph.
Sebagai contoh:
sumber
itu hanya dapat dimuat sementara dalam transaksi. Jadi, Anda dapat mengakses koleksi di repositori Anda, yang memiliki transaksi - atau yang biasa saya lakukan adalah
get with association
, atau setel fetchmode ke eager.sumber
Saya pikir Anda perlu OpenSessionInViewFilter untuk menjaga sesi Anda tetap terbuka selama rendering tampilan (tapi itu bukan praktik yang terlalu baik).
sumber
Data Musim Semi
JpaRepository
Data Musim Semi
JpaRepository
mendefinisikan dua metode berikut:getOne
, Yang mengembalikan sebuah proxy yang entitas yang cocok untuk menetapkan@ManyToOne
atau@OneToOne
asosiasi orangtua ketika bertahan entitas anak .findById
, yang mengembalikan entitas POJO setelah menjalankan pernyataan SELECT yang memuat entitas dari tabel terkaitNamun, dalam kasus Anda, Anda tidak menelepon
getOne
ataufindById
:Jadi, saya menganggap
findOne
metode ini adalah metode yang Anda tetapkan dalamPersonRepository
. Namun,findOne
metode ini tidak terlalu berguna dalam kasus Anda. Karena Anda perlu mengambilPerson
bersama denganroles
koleksi, lebih baik menggunakanfindOneWithRoles
metode sebagai gantinya.Metode Data Musim Semi Kustom
Anda dapat mendefinisikan
PersonRepositoryCustom
antarmuka, sebagai berikut:Dan definisikan implementasinya seperti ini:
Itu dia!
sumber
Anda dapat melakukan hal yang sama seperti ini:
Cukup gunakan faqQuestions.getFaqAnswers (). Size () di controller Anda dan Anda akan mendapatkan ukuran jika daftar intialised malas, tanpa mengambil daftar itu sendiri.
sumber