Wpis z mikrobloga

#java #spring #hibernate

Mirki, mam kłopotz rozwiązaniem problemu n+1 w hibernate.

Problem wygląda mniej więcej tak:
Mam Klasę UserService, która przechowuje dane użytkownika pobrane przez narzędzie autoryzacji.

class User{
Integer codes;
String username;
}

Mam klasę-encję ConfUserData:
@Entity

class ConfUserData
@Column
Long id;
@Column
String anyVariableEnabled
@Column
Date lastModification
@Column
String state;
@ElementCollection
Set

Mam tu relację ONE TO MANY. ConfUserData może mieć wiele "codes".
Hibernate mapuje to tak, że powstaje nowa tabela ConfUserDataCodes, która łączy ConfUserData z wieloma 'codes'.

I teraz pytanie główne:
Chcę mieć informacje czy istnieje jakiś element o odpowiedniej wartości "state" i odpowiedniej "anyVariableEnabled" - dla każdego "codes" mojego użytkownika.

Zrobiłem custom query, które za pomocą joina sprawdza mi tabelę ConfUSerData, dla danego "codes", którego wyciągam z UserService. Czyli w skrócie: przeszukuje tabelę Conf
UserDataCodes, znajduje podany "codes" - po kluczu sprawdza wartości w ConfUserData dla danego codes i zwraca true/false.

Problem w tym, że występuje tu n+1 zapytań.
Mój kod wygląda tak:
UserService.getCodes().stream.map(this::getConfigurationInfo)....
W tym przypadku dla każdego "codes" użytkownika leci zapytanie do bazy, które szuka codes, sprawdza ConfUserData i zwraca wartość. Działać działa, ale wolałbym żeby szło jedno zapytanie do bazy.
Problem w tym, że nie mam pojęcia jak to zrobić.

Macie jakiś pomysł?
  • 4
@fegwegw: Dzięki za odpowiedź.
Chciałem użyć fetch joina, ale wydawało mi się, że używa się tego w przypadku, kiedy masz klasę @Entity z jakimś podzbiorem @ElementCollection @JoinTable itd..
Np. masz klasę School i klasę Student. Klasa School ma wiele Studentów. Za pomocą fetch joina mogę za pomocą jednego query zrobić coś w stylu (select wszystkich studentów z School + select każdego Studenta).

W moim przypadku mam kilkadziesiąt kodów i intuicyjnym jest
tak jak @fegwegw Ci podpowiedział użyj fetch joina, a żeby być precyzyjnym to pewnie left join fetch bo Twoja kolekcja pewnie może być pusta.
"select c from ConfUserData c left join fetch c.codes"