Problem: chcemy aby zapytania do naszych encji ściągały tylko te pola, które są nam potrzebne w danej sytuacji (np. do pokazania w specyficznej tabeli w UI).
Wymaganie: nasze rozwiązanie musi mieć możliwość przyjęcia dowolnej kompozycji filtrów.
Możliwe rozwiązania:
- Named Entity Graph ze standardu JPA.
- Projections - mechanizm z Spring Data
Zbadajmy je!
JPA Named Entity Graphs
Ten mechanizm pochodzi bezpośrednio ze specyfikacji JPA i jest wspierany przez repozytoria Spring Data. Aby go wykorzystać musimy najpierw zdefiniować graf na naszej encji. W owym grafie określimy, które pola mają być pobierane w ramach zapytania poprzez tzw. eager fetching.
Jak widać wykorzystanie Named Entity Graphs jest trywialne w tego typu prostym przykładzie. Istnieje jednak poważny problem w Hibernate (najpopularniejszej implementacji JPA), który uwidacznia się przy nieco bardziej złożonych modelach danych. W bibliotece jest bug wiszący od 2014, który uniemożliwia wykorzystanie Named Entity Graphs w klasach @Embedded oraz @MappedSuperclass. Jeżeli wykorzystujesz inną implementację, która nie ma tego typu ograniczeń, to możesz dowiedzieć się więcej o Named Entity Graphs z dokumentacji JavaEE oraz dokumentacji Spring Data.
Spring Data Projections
Jest to funkcjonalność spoza specyfikacji JPA i jest wspierana wyłącznie w repozytoriach Spring Data dla JPA. Wykorzystuje interfejsy, aby zdefiniować zakres danych, który chcesz pobrać w zapytaniu poprzez tzw. eadger fetching.
Jak widać to rozwiązanie zwraca tylko interfejs z polami projekcji, a nie encję, z której można by w dalszym przetwarzaniu pobrać pozostałe pola poprzez tzw. lazy fetching. Można to postrzegać jako minus tego mechanizmu, ale jest to też bezpieczniejsze podejście jeżeli wydajność jest kluczowa dla Twojej aplikacji. Projekcje z Spring Data mają też parę ciekawych opcji, których Named Entity Graphs nie zapewniają. Można o nich poczytać w Spring Data JPA Reference Manual.
Wykorzystanie w zapytaniach dynamicznych
Oba mechanizmy opisane w niniejszym artykule wymagają nieco wysiłku aby zmusić je do współpracy z dynamicznymi zapytaniami tworzonymi przez Spring Data Speifications. Normalnie dodajemy mechanizm specyfikacji do naszych repozytoriów poprzez rozszerzenie ich interfejsem JpaSpecificationExecutor<T>, który to zapewnia zamknięty zbiór metod akceptujących Specification<T> jako argument (opcjonalnie z argumentem Pageable oraz Sort). Konwencje Spring Data JPA domyślnie nie pozwolą nam użyć Specification<T> w naszych metodach. Z tego powodu nie możemy dodać własnych metod, które zwracałyby interfejsy projekcji lub miały nad sobą adnotacje @EntityGraph. Aby rozwiązać ten problem musimy rozszerzyć wewnętrzną funkcjonalność Spring Data - na szczęście mamy gotowe biblioteki, które to robią.
Dla Named Entity Graphs mamy bibliotekę spring-data-jpa-entity-graph. Należy jednak mieć na uwadze, że w przypadku Hibernate nadal nie rozwiąże to wcześniej wspomnianego buga.
Dla Spring Data Projections istnieje mała biblioteka zwana specification-with-projection. Jest też zgłoszenie od 2016 aby dodać tą funkcjonalność do głównej biblioteki.
Ten artykuł jest wynikiem naszej współpracy z Nextbuy - firmą dostarczającą w modelu SaaS platformę zakupową i przetargową, która łączy kupców i dostawców. Świadczymy dla nich usługi doradcze oraz wsparcie w pracach programistycznych. Jesteśmy wdzięczni, że zgodzili się upublicznić część dokumentów projektowo-rozwojowych powstałych, w wyniku tego. Możecie sprawdzić ich świetną platformę na www.nextbuy24.com
Czy potrzebujesz pomocy z którymś tematem poruszonym na naszym blogu? Jeżeli tak, skontaktuj się z nami. Możemy pomóc poprzez doradztwo oraz usługi audytowe lub zorganizować warsztaty szkoleniowe dla Twoich pracowników. Możemy także wspomóc proces wytwarzania oprogramowania w Twojej firmie poprzez outsourcing naszych programistów.