W pierwszej części pokazałem jak powinna wyglądać standardowa encja oraz konfiguracja modułu. W tej części będzie trochę teorii co powinna dostarczać klasa SelfManagedEntity.

Active Record

Wzorzec projektowy Active Record ma swoje korzenie w kartotekowych bazach danych. Dokładnie w ich implementacjach z lat 70tych kiedy ktoś wymyślił, że pracując na rekordzie warto mieć metody typu save, delete, czy next.
W roku 2003 Martin Fowler opisał ten wzorzec i wskrzesił go po czasach niebytu na maszynach COBOLowo-LINCowych.

Jakie metody potrzebujemy

W wersji podstawowej potrzebujemy trzy metody.

Statyczny get

Metoda pozwala na wyszukanie encji w bazie danych na podstawie identyfikatora. W naszym przypadku w momencie gdy w bazie nie będzie takiego obiektu to użyjemy AI do jego stworzenia.

Niestatyczny delete

Usuwa encję z bazy.

Niestatyczny save

Zapisuje encję do bazy danych. W zależności od okoliczności wykonuje INSERT albo UPDATE.

Dlaczego nie ma oddzielnej metody update?

Ponieważ wywołując get nie wiemy czy encja pochodzi z DB czy jest nowym tworem. Dlatego wywołanie update mogło by powodować nieintuicyjne zachowanie aplikacji.

Jakie pola potrzebujemy

Jak wspomniałem we wpisie dotyczącym AI pola, które są wstrzykiwanie przez DI powinny być oznaczone jako transient jeżeli chcemy korzystać z JPA.

Niestatyczny EntityManager

W praktyce jedyne pole, które jest wymagane. Pozwala na dokonywanie operacji w bazie danych.

Statyczny EntityManager

Dodatkowy EntityManager, który będzie wykorzystywany w metodach statycznych. W zamian można użyć

Statyczny Injector

Z którego będziemy pobierać EntityManagera w metodach statycznych. Oba rozwiązania siebie warte.

EntityCache

Mój wynalazek. Jeżeli wywołujemy metodę get to nie wiemy czy obiekt o danym identyfikatorze istnieje w aplikacji. Jeżeli istnieje to mogą pojawić się problemy z równoległym utrwalaniem. Jeżeli aplikacja jest pisana w modelu jeden użytkownik na raz (JSE) to warto wprowadzić dodatkowy mechanizm, który będzie sprawdzał czy nie utworzono już obiektu o danym identyfikatorze. W przypadku aplikacji rozproszonej (WEB-UI) cache powinien ograniczać się do zakresu sesji danego użytkownika.
Tym jak zaimplementowany jest cache nie będę się zajmować. Nie jest obowiązkowy i w praktyce każdy może go napisać po swojemu.

Dodatkowe metody

Nasza zabawka nie będzie kompletna bez kilku dodatkowych metod.

Statyczny count

Zwraca ilość encji danego typu w bazie danych.

Statyczny max i min

Zwracający maksymalną bądź minimalną wartość z danej kolumny dla danej encji.

Statyczny findBy

Zwracający listę encji dla których dane kolumny spełniają dane warunki. Łączymy operatorem AND

I w praktyce co tylko możesz sobie wyobrazić.

Problem

Metody statyczne nie mogą być dziedziczone. Zatem albo będziemy powtarzać kod albo coś wykombinujemy. Rozwiązanie jest stosunkowo proste, ale będzie wymagać wprowadzenia dodatkowego kodu do naszych encji. Cóż… takie życie.