14 marca 2007

Java Persistence - Rozdział 4 Język zapytań - sekcje 4.1 Przegląd oraz 4.2 Typy wyrażeń

Nie pamiętam, czy już o tym wspominałem, ale od ponad miesiąca jest dostępny egzamin Sun Certified Business Component Developer (SCBCD) for the Java Platform, Enterprise Edition 5 (CX-310-091). 4 z 11 sekcji dotyczą JPA, więc przy wymaganych 59% poprawnych odpowiedzi (36 z 61 pytań) wydaje się, że przestudiowanie specyfikacji daje solidne podstawy wierzyć, że egzamin jest do opanowania. Ciekaw jestem, czy jest już ktoś, kto przeszedł pomyślnie egzamin i może poszczycić się nim? Z wielkim zainteresowaniem wysłuchałbym rad jak tego dokonać.

Mając w głowie możliwość podejścia do egzaminu powracam do studiowania specyfikacji JPA. Tym razem pora na nowy rozdział 4 o języku zapytań - Chapter 4: Query Language. Rozdział przedstawia pełną specyfikację języka zapytań JPA.

Język zapytań JPA (dalej JPA-QL - ang. JPA Query Language) zdefiniowano do tworzenia zapytań do odczytywania encji i ich trwałego stanu. Dzięki JPA-QL twórca aplikacji może uniezależnić zapytania od konkretnej bazy danych.

JPA-QL jest rozszerzeniem języka zapytań EJB (dalej EJB-QL - ang. Enterprise JavaBeans Query Language). Udostępnia operacje związane z wykonywaniem zbiorczych operacji UPDATE oraz DELETE, operacji JOIN, GROUP BY, HAVING, projekcje (ang. projection) oraz podzapytania. Jak można było przekonać się w poprzednim rozdziale 3.6 Query API JPA-QL wspiera dynamiczne i statyczne zapytania oraz nazwane parametry. Wszystkie elementy języka są dostępne w obu typach zapytań - dynamicznych i statycznych.

4.1 Przegląd

JPA-QL jest językiem zapytań dynamicznych i statycznych (zdefiniowanych z użyciem adnotacji). Język JPA-QL może być zamieniony na język docelowy repozytorium danych, np. SQL (tutaj po raz pierwszy wspomina się o innych bazach danych niż bazy relacyjne, czy wręcz repozytoria danych. Mimo to, wydaje się, że specyfikacja JPA jest celowana w rynek baz relacyjnych, bo to one potrzebują wsparcia przy zamianie reprezentacji relacyjnej na obiektową i na odrót). Zamian JPA-QL na docelowy język bazy pozwala na przesunięcie odpowiedzialności za wykonanie zapytania bezpośrednio do motoru bazy danych, zamiast wykonywać go na instancjach encji podczas uruchomienia (co znacząco obciążałoby pamięć aplikacji JPA). Dzięki temu dostawca JPA ma możliwość zoptymalizowania zapytań przy zagwarantowaniu przez specyfikację JPA ich niezależności od samego dostawcy JPA i docelowej bazy danych.

JPA-QL korzysta z abstrakcyjnego modelu trwałego encji, wliczając ich powiązania, dostarczając operacji i wyrażeń do operowania na nim. Składnia JPA-QL jest zbliżona do SQL. Specyfikacji jasno wskazuje możliwość sprawdzenia poprawności zapytań JPA-QL zanim encje zostaną zainstalowane w środowisku uruchomieniowym.

Pojawia się wyjaśnienie, w którym specyfikacja tłumaczy wyrażenie abstrakcyjny schemat trwały (ang. abstract persistence schema), który odnosi się do abstrakcji schematu trwałego, tj. encji, ich stanu i zależności, na którym wykonywane są zapytania JPA-QL.

Zapytania mogą być definiowane za pomocą adnotacji oraz w deskryptorze XML. Zapytanie może korzystać z abstrakcyjnego schematu zbioru encji, które zdefiniowane są w tym samym PU (jednostka trwałości, ang. persistence unit). Wyrażenia ścieżkowe pozwalają na nawigację przez relacje zdefiniowane w PU.

Specyfikacja przypomina definicję PU, którą warto odnotować (bardzo krótka acz przedstawiająca sedno sprawy):

PU definiuje zbiór wszystkich klas, które są powiązane i zgrupowane w aplikacji, i które muszą być związane z pojedyńczą bazą danych.

4.2 Typy wyrażeń

Wyrażeniem JPA-QL może być wyrażenie SELECT, UPDATE bądź DELETE. Dowolne wyrażenie może być utworzone dynamicznie bądź zdefiniowane statycznie przy użyciu adnotacji bądź w deskryptorze XML. Zapytania mogą posiadać parametry.

4.2.1 Wyrażenia SELECT

Wyrażenie SELECT składa się z:
  • klauzuli SELECT, która określa typ zwracanych obiektów lub wartości
  • klauzuli FROM, która dostarcza deklaracji, które wyznaczają obszar działania wyrażeń zdefiniowanych w innych klauzulach zapytania
  • opcjonalnej klauzuli WHERE, która może ograniczać wyniki zapytania
  • opcjonalnej klauzuli GROUP BY, która pozwala na grupowanie wyników zapytania
  • opcjonalnej klauzuli HAVING, która pozwala na filtrowanie według grup
  • opcjonalnej klauzuli ORDER BY, która może być używana do uporządkowania wyników zapytania
Notacja BNF przedstawia się następująco:

select_statement :: = select_clause from_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause]

Wyrażenie SELECT musi zawierać klauzulę SELECT oraz FROM podczas, gdy pozostałe klauzule są opcjonalne.

Query query = em
.createQuery("SELECT p.imie, p.nazwisko, p.dzienUrodzin FROM Pracownik p "
+ "WHERE p.nazwisko LIKE 'L%' GROUP BY p.imie, p.nazwisko, p.dzienUrodzin HAVING p.dzienUrodzin > :dzisiaj ORDER BY p.dzienUrodzin");
query.setParameter("dzisiaj", dzisiaj, TemporalType.DATE);

4.2.2 Wyrażenia UPDATE i DELETE

Wyrażenie UPDATE i DELETE umożliwiają wykonanie zbiorczych operacji na zbiorze encji.

W notacji BNF przedstawiają się następująco:

update_statement :: = update_clause [where_clause]

delete_statement :: = delete_clause [where_clause]

Klauzule UPDATE (update_clause) oraz DELETE (delete_clause) określają typ encji, na których zostanie wykonana operacja, modyfikacji bądź skasowania, odpowiednio. Klauzula WHERE (podobnie jak w wyrażeniu SELECT) służy do ograniczenia zasięgu operacji.

Przejrzałem nadchodzące rozdziały i zauważyłem użycie zapytań typu JOIN oraz FETCH JOIN, które nie dawały mi ostatnio spokoju. W końcu nastąpi moment, w którym wierzę, że uda mi się zrozumieć ich działanie (i będę mógł mądrować się jakie to one są proste! ;-)).