Spring Data JPA dostarcza narzędzia obsługi repozytorium danych dla Java Persistence API (JPA).
Największą zaletą tego rozwiązania jest ułatwienie procesu zarządzania dostępem do źródeł danych.
Mamy na przykład tabelę w bazie danych, dla której przygotowaliśmy encję w Hibernate i chcemy jej od razu używać.
Tak po prostu.
Dzięki Spring Data JPA nie musimy wymyślać koła od nowa, aby móc wykonywać najprostsze operacje bazodanowe w stylu CRUD.
Od razu dostajemy gotowe interfejsy, które posiadają odpowiednio przygotowane podstawowe metody dostępowe.
Możemy z łatwością tworzyć, usuwać i modyfikować rekordy bez przesadnego przeładowania kodem.
Oczywiście jako fani Spring Boot-a, od razu zabieramy się do przedstawienia szablonu startera, dzięki któremu uzyskujemy odpowiedni zestaw zależności.
Wspomnijmy tylko, że w tym rozdziale kursu bazujemy na - ciągle jeszcze powszechnie używanym - Spring Boocie w wersji 1.x, który współpracuje z wersją Spring Data JPA 1.x.
W rozdziale
Spring Data JPA 2.x - Podstawowe funkcjonalności przedstawiamy najnowszą wersję działającą ze Spring Boot 2. Różnice nie są duże. Polegają głównie na wprowadzeniu udogodnień znanych
z Javy 8 oraz na zmianie nazewnictwa niektórych metod
find (ale o tym szerzej we wspomnianym rozdziale).
Wracając do meritum, tak wygląda nasza zależność szablonu startowego
data-jpa:
Po zbudowaniu projektu możemy przystąpić do przyjrzenia się kilku istotnym interfejsom, które dostajemy razem ze starterem.
Będziemy z nich korzystać (w szczególności z jednego z nich) podczas wykonywania operacji na danych w systemie.
Podstawowy interfejs - CrudRepository
Dostarcza podstawowe wersje metod dla operacji typu CRUD (Create, Read, Update, Delete):
Wytłumaczenie kolejnych kategorii metod wydaje się być zwykłą formalnością, ale podsumujmy:
save |
- zapisuje encje w bazie (pojedynczo lub cały zbiór) |
findOne |
- wyszukuje encje po id |
exists |
- sprawdza po id czy encja istnieje |
findAll |
- pobiera wszystkie encje zwracając interfejs Iterable |
count |
- zlicza wszystkie encje |
delete |
- usuwa encje po podanym obiekcie lub zbiorze obiektów |
deleteAll |
- usuwa wszystkie encje |
|
|
PagingAndSortingRepository rozszerzający CrudRepository
Dorzuca - w stosunku do tego co ma
CrudRepository - metody wyciągające encje w sposób posortowany i stronicowany:
Metody te rozumiemy w ten sposób:
findAll(Sort sort) |
- pobiera wszystkie encje (z uwzględnieniem sortowania) i zwraca interfejs Iterable |
findAll(Pageable pageable) |
- pobiera wszystkie encje (z uwzględnieniem stronicowania) i zwraca interfejs strony: Page |
JPARepository rozszerzający PagingAndSortingRepository
Dostarcza bardziej precyzyjne wersje metod, np. poprzez zwracanie interfejsu
List zamiast
Iterable
oraz dodaje nowe metody:
W tym przypadku wytłumaczenie kolejnych kategorii metod wygląda tak:
findAll |
- pobiera wszystkie encje (ew. sortowane), albo encje po zbiorze idików i zwraca interfejs List |
save |
- zapisuje encje w bazie, podane w postaci zbioru bazującego na interfejsie Iterable |
flush |
- wymusza odzwierciedlenie wykonanych operacji (na encjach) na bazie |
saveAndFlush |
- zapisuje encje i wymusza odzwierciedlenie wykonanych operacji (na encjach) na bazie |
deleteInBatch |
- usuwa całą partię encji, podaną w postaci zbioru bazującego na interfejsie Iterable |
deleteAllInBatch |
- usuwa wszystkie encje w jednej partii |
getOne |
- pobiera encję po id |
findAll(Example...) |
- pobiera encje po podanej klasie przykładu (możliwe w wersji z sortowaniem) |
Zatrzymajmy się w tym miejscu na chwilę, aby zauważyć jedną rzecz. Dwie ostatnie metody, pobierające obiekty po klasie przykładu (
Example),
znajdują się w tym interfejsie nieprzypadkowo, mimo iż mają niewiele wspólnego z dziedziczonymi klasami. Okazuje się bowiem, że
interfejs
JPARepository dziedziczy nie tylko z
PagingAndSortingRepository, ale
również z interfejsu
QueryByExampleExecutor. Ten ostatni jest odpowiedzialny za dostarczenie deklaracji metod
operujących właśnie na klasie przykładu.
JPARepository w akcji
No dobrze, zobaczmy zatem teraz przykład, który zobrazuje nam dokładnie jak działa
JPARepository. Mamy klasę
ItemServiceImpl implementującą doskonale znany nam już interfejs
ItemService (znany dla czytających rozdziały po koleji ;)).
Mamy również interfejs, za pomocą którego będziemy wykonywać operacje na itemach. Interfejs ten dziedziczy z
JPARepository i..nie posiada własnych metod (jedynie dziedziczy metody):
Wstrzykujemy obiekt interfejsu
ItemRepository do naszego serwisu
ItemServiceImpl i już możemy używać metod,
które są dostępne wśród wszystkich dziedziczonych przez nas interfejsów (
ItemRepository -
JPARepository
-
PagingAndSortingRepository -
CrudRepository).
Dla naszego interfejsu określiliśmy również dwa parametry typu. Pierwszy -
Item, wskazuje na klasę encji, a drugi -
Long, reprezentuje typ klucza jaki jest używany przez encję
Item.
Możemy teraz w naszym serwisie zdefiniować metodę do pobierania itemu po id (
getAppaItem) i wykonać w niej operację
pobrania
encji po id:
Oczywiście nasz interfejs nie musi być pusty. W miarę potrzeby możemy do niego dokładać własne metody, a nawet tworzyć całe zapytania, ale o tym już w kolejnych rozdziałach.
Na koniec zobaczmy jeszcze jak wygląda zbiorcza lista metod, jakie możemy wykonać na naszym
ItemRepository, zgodnie z tym co pisaliśmy o dziedziczeniu interfejsów:
Nasza rekomendacja
W projekcie można zaimplementować każdy z powyższych interfejsów, niemniej ze względu na to, że interfejs JPARepository
ma najszerszy zakres, warto od samego początku używać własnie jego. Nawet jeśli w początkowej fazie wydaje się nam, że nie będziemy potrzebować sortowania, stronicowania,
bądź też operowania na klasie przykładu, to prędzej czy później przychodzi taki czas, że projekt się rozrasta, a początkowe założenia się zmieniają
i nagle może być wymagane dodanie wspomnianych funkcjonalności. Profesjonalni programiści powinni być na to przygotowani już wcześniej, prawda?
Używamy w StartAPPa
We wszystkich kursach aplikacji kod operuje na warstwach kontrolera, serwisu i repository. Każda klasa serwisu posiada wstrzyknięty interfejs, za pomocą którego
wykonujemy wymagane operacje.
[TEORIA i PRAKTYKA] Strefa doładowania wiedzy
W tej strefie znajdziesz wszystko co niezbędne, aby komfortowo uczyć się Hibernate'a.
Doskonale opisany kod nie zawiera zbędnych komplikacji, tylko samą esencję w postaci praktycznych przykładów.
Tutaj odnajdziesz wszystko co jest istotne w danym temacie. Otrzymujesz pakiet złożony z kilku projektów
wraz z obszernym wytłumaczeniem kodu.
Linki
https://docs.spring.io/spring-data/jpa/docs/1.11.16.RELEASE/reference/html