VÝVOJ PODNIKOVÝCH APLIKACÍ NA PLATFORMĚ JAVA - PŘEDNÁŠKA Zbyněk Šlajchrt Část 8.
Dědičnost entit Základní vlastnost OOP Sdílení stavu a chování mezi třídami uspořádanými do hierarchií Na rozdíl od relací nemají relační databáze koncept pro dědičnost mezi tabulkami Lze zařídit dodatečně - 3 strategie Single-table-per-hierarchy Joined-subclass Table-per-concrete-class 2
Příklad dědičnosti 3
Příklad dědičnosti - Java 4
Single-table-per-hierarchy Tato strategie mapuje celou hierarchii tříd entit do jedné tabulky Jedna tabulka ITEM a v ní atributy pro Item, Book a CD Default strategie Tabulka obsahuje speciální sloupec pro rozlišení entit – tzv. discriminator column Lze konfigurovat Hodnotu, kterou je identifikována entita ve sloupci, lze určit umístěné na třídu 5
Single-table-per-hierarchy 6 IDDTYPETITLEPRICEDESCRIPTIONMUSICCOMPANYISBN... 1ItemPen1,20Nice pen 2CDABBA20,00RemakeEMI 3BookBible1,00God's book1 4CDBeatles30,00best of...EMI ITEM ID DTYPE TITLE PRICE DESCRIPTION MUSICCOMPANY ISBN NUMBEROFPAGES... ITEM ID DTYPE TITLE PRICE DESCRIPTION MUSICCOMPANY ISBN NUMBEROFPAGES...
Single-table-per-hierarchy Výhody Nejjednodušší – snadná správa Nejvýkonnější strategie – žádné joiny, subselecty atd. Nevýhody Sloupce potomků musí být NULLABLE – big problem! Model není normalizovaný, jelikož sloupce patřící potomkům nemusí být používané 7
Joined-strategy Tato strategie mapuje entity do samostatných tabulek Tabulka entity obsahuje pouze sloupce pro atributy deklarované ve třídě entity Zděděný stav se mapuje do tabulky předka Tabulka kořenové entity (Item) znovu obsahuje discriminator column pro rozlišení řádek entit usnadňuje polymorfní dotazy v případě víceúrovňových hierarchií Kořenovou entitu (Item) je třeba 8
Joined-strategy 9 ITEM ID DTYPE TITLE PRICE DESCRIPTION ITEM ID DTYPE TITLE PRICE DESCRIPTION CD ID MUSICCOMPANY NUMBEROFCDS TOTALDURATION GENDER CD ID MUSICCOMPANY NUMBEROFCDS TOTALDURATION GENDER BOOK ID ILLUSTRATIONS ISBN NUMBEROFPAGES PUBLISHER BOOK ID ILLUSTRATIONS ISBN NUMBEROFPAGES PUBLISHER
Joined-strategy Výhody Vlastnosti potomků mohou být NOT NULL Model je normalizovaný Nevýhody Není tak výkonná jako Single-table-per-hierarchy 10
Single-per-concrete-class Každá entita je mapovaná do vlastní tabulky včetně zděděných vlastností Schéma není normalizované Sloupce z kořenové tabulky se opakují v tabulkách potomků Není zde žádný discrimator column Primární klíč je sdílený – nesmí se vyskytovat dvakrát napříč tabulkami v jedné hierarchii Nepovinná strategie ve specifikaci JPA 2.0 přenositelné aplikace by jej neměly používat 11
Single-per-concrete-class 12 ITEM ID TITLE PRICE DESCRIPTION ITEM ID TITLE PRICE DESCRIPTION CD ID TITLE PRICE DESCRIPTION MUSICCOMPANY NUMBEROFCDS TOTALDURATION GENDER CD ID TITLE PRICE DESCRIPTION MUSICCOMPANY NUMBEROFCDS TOTALDURATION GENDER BOOK ID TITLE PRICE DESCRIPTION ILLUSTRATIONS ISBN NUMBEROFPAGES PUBLISHER BOOK ID TITLE PRICE DESCRIPTION ILLUSTRATIONS ISBN NUMBEROFPAGES PUBLISHER
Single-per-concrete-class Výhody Vlastnosti mohou být NOT NULL Může být jednodušší mapování na legacy schéma Nevýhody Model není normalizovaný, opakování sloupců předka Náročné na implementaci polymorfních dotazů Buď více selectů do všech tabulek hierarchie – POMALÉ! Nebo pomocí SQL UNION – podporují pouze některé DB Lépe se této strategii vyhýbat 13
Typy předků Entita standardní entita Abstraktní entita z hlediska JPA totéž jako entita Ne-entita také se někdy označují jako tranzientní třídy vlastnosti zděděné z tohoto předka se nemapují do DB Mapovaný předek Ne-entita, její vlastnosti se však mapují do tabulky potomka – anotuje Podobnost s embedded entity 14
Dotazovací aparát Doposud jsme probírali pouze vyhledávání podle primárního klíče EntityManager::find a EntityManager::getReference JPA 2.0 obsahuje specifikaci jazyka JPQL Objektově-orientovaný dotazovací jazyk inspirovaný SQL Vývojář při sestavování dotazu pracuje s objekty nikoliv s prostými hodnotami Tečková notace pro přístup k vlastnostem entit Client.address.street 15
Query API Dotaz se vytváří voláním metody createQuery na objektu EntityManager Parametrem je výraz v syntaxi jazyka JPQL Vrací objekt s rozhraním javax.persistence.Query Metoda getSingleResult() vrací jediný objekt pokud není objekt právě jeden Metoda getResults() vrací seznam – i prázdný 16
Parametrizovaný dotaz Podobně jako v JDBC, i v JPQL lze dotazy parametrizovat Parametry lze definovat jménem nebo pořadím Definice pojmenovaného parametru na místo hodnoty ve výrazu se zapíše název parametru s prefixem : na místo hodnoty ve výrazu se zapíše pořadové číslo parametru s prefixem ? indexováno od 1 Hodnota parametru se nastavuje setParameter() 17
Parametrizovaný dotaz 18 Nastavení parametrů podle jejich pořadí: Nastavení parametrů podle jejich názvu:
Časové parametry Pro zadávání hodnot časových parametrů se používá jiných metod setParameter(name/position, Date, TemporalType) setParameter(name/position, Calendar, TemporalType) TemporalType je výčtový typ, který specifikuje databázový časový typ, do kterého se konvertuje typ java.util.Date nebo java.util.Calendar DATE TIME TIMESTAMP 19
Stránkování výsledků V případě velkého počtu výsledků lze omezit jejich počet Query::setFirstResult(index) Oznamuje dotazu, od kterého indexu má vrátit první výsledek Query::setMaxResult(max) Oznamuje dotazu maximální počet výsledků v seznamu 20
Hints Někteří dodavatelé JPA poskytují extra funkcionalitu, kterou lze použít při dotazování Např. JBoss EJB 3.0 (obsahuje Hibernate) umožňuje specifikovat timeout dotazu Pro nastavení extra funkcionality se volá setHint(hintName, hintValue) query.setHint("org.hibernate.timeout", 1000); 21
FlushMode dotazu Ovlivňuje způsob synchronizace stavu entit s databází Někdy se hodí, aby během zpracování dotazu platil jiný flush mod např. chceme zabránit, aby EntityManager provedl automatický flush před dotazem – mod AUTO mu to umožňuje Dočasný flush mod se nastavuje Query::setFlushMode(flushMode) query.setFlushMode(FlushModeType); 22
JPQL SELECT Klauzule SELECT slouží k definici výběru dat z databáze Výsledkem může být entita atribut entity nově zkonstruovaný objekt hodnota agregační funkce sekvence výše uvedených výsledků Pro odkazování na atributy entit se používá tečková konvence 23
SELECT - Syntaxe 24 SELECT FROM [WHERE ] [ORDER BY ] [GROUP BY [HAVING ]]
SELECT – Příklady SELECT c FROM Customer c Vrací seznam všech zákazníků List SELECT c.firstName FROM Customer c Vrací seznam křestních jmen všech zákazníků List SELECT c.firstName, c.lastName FROM Customer c Vrací seznam křestních jmen a příjmení (pole velikosti 2) List SELECT c.address FROM Customer c Vrací seznam adres všech zákazníků List 25
SELECT – Příklady SELECT c.address.country.code FROM Customer c Ukázka tečkové notace. Vrací seznam kódů zemí v adresách zákazníků. List SELECT NEW cz.vse.javaee.prednaska8.CustomerDTO (c.firstName, c.lastName, c.address.city) FROM Customer c Vrací seznam objektů CustomerDTO vytvořených pro každého zákazníka. Do konstruktoru se předávají údaje zákazníka. List 26
SELECT – Příklady SELECT DISTINCT c.firstName FROM Customer c Vrací seznam křestních jmen všech zákazníků bez duplicit. List SELECT count(c) FROM Customer c Vrací skalární hodnotu rovnu počtu všech zákazníků. List, velikost 1, volat Query::getSingleResult() Agregační funkce AVG - průměr COUNT - počet MAX - maximum MIN - minimum SUM - součet 27
Klauzule FROM Definuje entity v dotazu Alias entity může být použit v dalších klauzulích SELECT, WHERE,... Příklady: FROM Customer c FROM Customer AS c FROM Customer c, Account a FROM Customer c, IN(c.accounts) a 28
Klauzule WHERE Definuje podmínkový výraz pro omezení výsledků používá se v SELECT, UPDATE, DELETE Příklady: WHERE c.firstName='Josef' WHERE c.firstName='Josef' AND c.lastName='Novák' WHERE a.deposit NOT BETWEEN 1000 AND WHERE c.address.country IN ('CZ', 'SK') WHERE c. LIKE '%vse.cz' % - více-znakový wildcard _ - jednoznakový wildcard 29
Operátory ve WHERE =, >, =,, [NOT] BETWEEN [NOT] LIKE [NOT] IN IS [NOT] NULL IS [NOT] EMPTY [NOT] MEMBER OF AND, OR V Javě se druhý operand nevyhodnocuje, pokud hodnota prvního určuje výsledek V JPQL se na toto nedá spolehnout 30
Subqueries Vnořené dotazy se používají v klauzulích WHERE a HAVING Příklady SELECT acc FROM Account acc WHERE acc.deposit= (SELECT MAX(a.deposit) FROM Account a) Vybere účet s největším vkladem V podstatě dva nezávislé dotazy SELECT c FROM Customer c WHERE 1000 > (SELECT SUM(a.deposit) FROM c.accounts AS a) Vybere klienty, kteří mají na svých účtech méně než 1000 Kč Vnořený dotaz je svázaný s hlavním dotazem 31
Subqueries – ALL, ANY, SOME Tyto operátory se používají pro vnořené dotazy, které vracejí více řádek ALL – logická operace musí platit pro všechny výsledky vnořeného dotazu ANY (SOME), - Operace musí platit aspoň pro jeden výsledek vnořeného dotazu Příklad: ... FROM Client c WHERE 100 < ALL (SELECT a.deposit FROM c.accounts AS a) Vybere klienty, kteří mají na svých všech účtech více než
Subqueries - EXISTS Operátor EXISTS vrací true výsledek obsahuje jeden nebo více výsledků Příklad: FROM Client c WHERE EXISTS (SELECT a FROM c.accounts AS a WHERE a.deposit > 100) Vrací pouze ty klienty, kteří mají aspoň na jednom účtu uloženo více jak 100 Kč 33
Klauzule ORDER BY ORDER BY se používá k seřazení výsledků dotazu Výsledky jsou seřazeny podle atributů entity uvedených v klauzuli Uvádí se i směr seřazení – vzestupně ASC, sestupně DESC Příklady: SELECT c FROM Customer c ORDER BY c.lastName, c.firstName SELECT a FROM Account a ORDER BY a.deposit DESC, a.client.lastName ASC, a.client.firstName ASC 34
Klauzule GROUP BY GROUP BY se používá k seskupení entit Skupina je tvořena entitami, které mají stejnou hodnotu atributů uvedených v GROUP BY Výsledek může obsahovat pouze skupinové atributy (z GROUP BY) a hodnoty agregačních funkcí aplikovaných na ne-skupinové atributy entit. Příklad: SELECT a.client, sum(a.deposit) FROM Account a GROUP BY a.client Výsledek v seznamu je klient a součet vkladů na jeho účtech 35
Klauzule HAVING Používá se pro filtrování dotazů sestavených pomocí GROUP BY Podmínku může obsahovat pouze agregační funkce nad atributy, které se vyskytují v klauzuli SELECT Příklad: SELECT a.client, sum(a.deposit) FROM Account a GROUP BY a.client HAVING sum(a.deposit) > 1000 Vybere klienty, kteří mají na svých účtech v souhrnu vyšší částku než 1000 Kč 36
Příkaz DELETE Určeno pro dávkové odstraňování entit Syntaxe: DELETE FROM [[AS] ] [WHERE ] Příklad: DELETE FROM Client AS c WHERE c.firstName='Karel' Smaže všechny Karly 37
Příkaz UPDATE Určeno pro dávkovou aktualizaci entit Syntaxe: UPDATE [[AS] ] SET {, }* [WHERE ] Příklad: UPDATE Account AS a SET a.deposit=a.deposit*1.01 where a.client.firstName='Josef' Připíše 1% ze zůstatku všem Josefům 38
INNER JOIN V klauzulích není možné používat atributy-kolekce Často je ale zapotřebí s nimi pracovat Operátor IN přiřazuje vybrané kolekci alias lze pak s tímto alias pracovat, jako by to byla entita Příklad: SELECT a FROM Client c, IN(c.accounts) a Vrátí všechny účty patřící nějakým klientům Alternativní zápis: SELECT a FROM Client c INNER JOIN c.accounts a 39
LEFT JOIN LEFT JOIN umožňuje vybírat také entity, které nemají nastavenu požadovanou vazbu Atributy protější entity mají ve výsledku hodnotu NULL Příklad: SELECT c.firstName, c.lastName, p.number FROM Client c LEFT JOIN c.phoneNumbers p 40 JosefNovák JosefNovák KarelVodička JanMalýNULL
Fetch Joins Umožňuje nahrát asociované entity, i když má vazba nastaven FetchType jako LAZY Příklad: MailBox – Messages (1:N) SELECT mbox FROM MailBox mbox INNER JOIN FETCH mbox.messages Bez FETCH bychom museli nahrát entity zpráv v Javě pomocí cyklu – problém s výkonností 41
Dodatek: JPQL Funkce LOWER(String), UPPER(String) TRIM([[LEADING|TRAILING|BOTH] [trimchar] FROM] String) CONCAT(String1, String2) LENGTH(String) LOCATE(String1, String2 [, start]) – hledá řetězec SUBSTRING(String, start, length) ABS(number), SQRT(double), MOD(int, int) 42
Dodatek: JPQL Funkce CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP Agregační funkce: COUNT, MAX, MIN, AVG, SUM DISTINCT – eliminuje duplicity hodnoty null jsou automaticky eliminovány 43
Zdroje Burke, Bill – Monson-Haefel, Richard; Enterprise Java Beans 3.0; O'Reilly Goncalves, Antonio; Beginning Java EE 6 Platform With GlassFish 3; APRESS 44