W dzisiejszej i jutrzejszej lekcji omówimy podstawy JPA — standardu, który znacznie upraszcza obsługę bazy danych z poziomu aplikacji. W pierwszej części lekcji zobaczymy sam JPA, w kolejnej zaś nauczymy się używać go we własnym projekcie.
JPA to standard z grupy tzw. ORM (ang. Object-Relational Mapping), co w wolnym tłumaczeniu oznacza mapowanie z modelu obiektowego (takiego, jaki używamy w aplikacjach Java) do modelu relacyjnego (takiego, z jakiego korzystają bazy danych). Oczywiście założeniem jest, żeby pracę programisty uprościć, a nie utrudnić, dlatego starano się zautomatyzować jak najwięcej rzeczy.
Lekcja
Aby korzystać z JPA będziemy potrzebowali tzw. providera — biblioteki, która dostarcza implementację standardu JPA (JPA to tylko zbiór kontraktów, tzn. opisów, jakie funkcje mają być realizowane i w jaki sposób — sami możemy wybrać lub stworzyć implementację, która będzie się tym zajmowała)
Tak naprawdę aby korzystać z JPA będziemy potrzebowali jednej adnotacji na każdej klasie oraz jednej na jej polu (identyfikatorze), którą chcemy też przechowywać w bazie danych (tak, jednej!). Jednocześnie możemy (i będziemy) modyfikować domyślne zachowanie JPA za pomocą dodatkowych adnotacji aby powiedzieć dokładnie, co chcemy, i w jaki sposób, żeby było zrobione. To kolejny przykład elastyczności i wygody, którą dostajemy dzięki podejściu convention-over-configuration.
Adnotacje w JPA
W przypadku baz danych (jak pewnie pamiętacie z ostatniej lekcji) mówimy o encjach i tak najważniejszą adnotacją w przypadku JPA jest właśnie @Entity. Adnotacja ta nie wymaga żadnych parametrów (możemy wybrać nazwę — pewnego rodzaju alias, używany później w zapytaniach, ale zostaniemy przy domyślnym — nazwie klasy), umieszczamy ją nad całą klasą, która ma być mapowana:
@Entity
public class Kot {
@Id
private Long id;
//...
}
Klasa taka, którą adnotujemy za pomocą @Entity, musi mieć publiczne gettery i settery dla każdego pola. Założenia przyjęte przez JPA w takiej sytuacji są następujące:
- tabela nazywa się tak jak klasa
- kolumny nazywają się tak, jak pola i są odpowiedniego typu z możliwością wpisania null
Powyżej widzimy także adnotację @Id — wskazuje nam ona, że dane pole jest identyfikatorem (unikalnym) tego obiektu. Najczęściej jest to pole typu Long o nazwie id lub podobnej. Bardzo często można spotkać się z adnotacją @GeneratedValue, co wskazuje, że identyfikator ten jest generowany automatycznie w momencie zapisu do bazy danych.
Zmiana parametrów tabeli
Bardzo często mamy już gotową bazę danych, którą chcemy zmapować i nie chcąc zmieniać jej struktury musimy dopasować nasze mapowanie (np. nazwę tabeli). Służy do tego adnotacja @Table — najczęściej wykorzystujemy jej parametr name, jak na poniższym przykładzie:
@Entity
@Table(name="koty")
public class Kot {
//...
}
Taki zapis spowoduje, że klasa Kot będzie mapowana na tabelę ‘koty’ zamiast domyślnej tabeli ‘Kot’
Zmiana parametrów kolumny
Podobnie jak w przypadku tabeli, domyślną nazwą kolumny jest nazwa pola. Najczęściej jednak nie jest to zgodne z konwencją nazewnictwa w bazie danych (gdzie często zamiast camelCase używamy nazw_z_podkreslnikami). Aby zmienić nazwę kolumny lub zmodyfikować jej atrybuty możemy użyć adnotacji @Column jak na przykładzie poniżej:
@Entity
@Table(name="koty")
public class Kot {
@Column(name="imie_kota", nullable=false)
private String imieKota;
//...
}
Widzimy tutaj dwie rzeczy: po pierwsze wskazujemy, że pole imieKota będzie zapisywane w kolumnie o nazwie imie_kota, na dodatek nie może mieć wartości NULL (ustawiliśmy atrybut nullable na false [domyślnie jest true] — jeśli spróbujemy zapisać w bazie danych obiekt, który w tym polu będzie miał wartość null, otrzymamy błąd bazy danych.
Uwaga! Bardzo często będziemy mieli do wyboru dwie adnotacje o takiej samej nazwie, np:
- javax.persistence.Entity
- org.hibernate.annotations.Entity — ta adnotacja dziedziczy po powyższej
Jest to spowodowane tym, że framework dodaje nowe możliwości i opcje. Zasadniczo, o ile nie potrzebujemy naprawdę czegoś, co oferuje biblioteka, powinniśmy używać adnotacji z pakietu javax.persistence, ponieważ są to adnotacje standardowe JPA — korzystanie tylko z tych adnotacji pozwoli w przyszłości podmienić implementację JPA tylko za pomocą konfiguracji.
To ogólna zasada, o ile możliwe, powinniśmy korzystać ze standardów a nie z ich rozszerzeń zawsze, kiedy jest to możliwe.
EntityManager
EntityManager to standardowy sposób wykonywania operacji na obiektach w standardzie JPA. Jak zobaczymy w drugiej części lekcji, skonfigurujemy fabrykę (czyli sposób, w jaki będą automatycznie tworzone EntityManagery), dzięki czemu będziemy mogli używać EntityManagerów w naszych klasach.
Na dzisiaj ważne jest, żeby pamiętać o tym, że EntityManager to nasz ‘most’ pomiędzy bazą danych a naszą aplikacją.
EntityManager vs Session
Powód, dla którego poruszamy dzisiaj ten temat (o tym, jak go używać powiemy sobie jutro) jest związany z alternatywnym sposobem, z którym możemy się spotkać w wielu tutorialach, a mianowicie Sesją (SessionFactory i Session). Role Session oraz EntityManager są podobne, Session ma nieco większe możliwości, ale EntityManager jest częścią standardu (Session nie). Ma tu zastosowanie zasada, o której wspominałem wcześniej — jeśli nie potrzebujemy koniecznie funkcjonalności Session, używajmy standardów — EntityManagera. Szerzej na ten temat wypowiedział się Emmanuel Bernard, Architekt w zespole pracującym nad Hibernate w krótkim wywiadzie , podsumowując w skrócie można posłużyć się cytatem: “We encourage people to use the EntityManager” .
W drugiej części
W drugiej części (już jutro) zobaczymy, jak dołączyć JPA do naszego projektu i Springa oraz jak korzystać z JPA w naszych klasach DAO.
Jeśli uważasz powyższą lekcję za przydatną, mamy małą prośbę: polub nasz fanpage. Dzięki temu będziesz zawsze na bieżąco z nowymi treściami na blogu ( i oczywiście, z nowymi częściami kursu Javy). Dzięki!