440 likes | 545 Views
VÝVOJ PODNIKOVÝCH APLIKACÍ NA PLATFORMĚ JAVA - PŘEDNÁŠKA. Zbyněk Šlajchrt http://java.vse.cz/4it447/HomePage. Část 8. Dědičnost entit. Základní vlastnost OOP Sdílení stavu a chování mezi třídami uspořádanými do hierarchií
E N D
VÝVOJ PODNIKOVÝCH APLIKACÍ NA PLATFORMĚ JAVA - PŘEDNÁŠKA Zbyněk Šlajchrt http://java.vse.cz/4it447/HomePage Čá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
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 pomocí @DiscriminatorColumn • Hodnotu, kterou je identifikována entita ve sloupci, lze určit pomocí @DiscriminatorValue umístěné na třídu
Single-table-per-hierarchy 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é
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 • Kořenovou entitu (Item) je třeba anotovat @Inheritance(strategy=Inheritance.JOINED)
Joined-strategy BOOK ID ILLUSTRATIONS ISBN NUMBEROFPAGES PUBLISHER ITEM ID DTYPE TITLE PRICE DESCRIPTION CD ID MUSICCOMPANY NUMBEROFCDS TOTALDURATION GENDER
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
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
Single-per-concrete-class BOOK ID TITLE PRICE DESCRIPTION ILLUSTRATIONS ISBN NUMBEROFPAGES PUBLISHER ITEM ID TITLE PRICE DESCRIPTION CD ID TITLE PRICE DESCRIPTION MUSICCOMPANY NUMBEROFCDS TOTALDURATION GENDER
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
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 se @MappedSuperclass • Podobnost s embedded entity
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
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ý
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()
Parametrizovaný dotaz Nastavení parametrů podle jejich názvu: Nastavení parametrů podle jejich pořadí:
Č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
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
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);
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);
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
SELECT - Syntaxe SELECT <select expression> FROM <from clause> [WHERE <conditional expression>] [ORDER BY <order by clause>] [GROUP BY <group by clause> [HAVING <having clause>]]
SELECT – Příklady • SELECT c FROM Customer c • Vrací seznam všech zákazníků • List<Customer> • SELECT c.firstName FROM Customer c • Vrací seznam křestních jmen všech zákazníků • List<String> • SELECT c.firstName, c.lastName FROM Customer c • Vrací seznam křestních jmen a příjmení (pole velikosti 2) • List<Object[2]> • SELECT c.address FROM Customer c • Vrací seznam adres všech zákazníků • List<Address>
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<String> • 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<CustomerDTO>
SELECT – Příklady • SELECT DISTINCT c.firstName FROM Customer c • Vrací seznam křestních jmen všech zákazníků bez duplicit. • List<String> • SELECT count(c) FROM Customer c • Vrací skalární hodnotu rovnu počtu všech zákazníků. • List<Long>, velikost 1, volat Query::getSingleResult() • Agregační funkce • AVG - průměr • COUNT - počet • MAX - maximum • MIN - minimum • SUM - součet
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
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 100000 • WHERE c.address.country IN ('CZ', 'SK') • WHERE c.email LIKE '%vse.cz' • % - více-znakový wildcard • _ - jednoznakový wildcard
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
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
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ž 100
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č
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
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
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č
Příkaz DELETE • Určeno pro dávkové odstraňování entit • Syntaxe: • DELETE FROM <entity_name> [[AS] <alias>] [WHERE <condition>] • Příklad: • DELETE FROM Client AS c WHERE c.firstName='Karel' • Smaže všechny Karly
Příkaz UPDATE • Určeno pro dávkovou aktualizaci entit • Syntaxe: • UPDATE <entity_name> [[AS] <alias>] SET <update_statement> {, <update_statement>}* [WHERE <condition>] • 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
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
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 Josef Novák 656787377 Josef Novák 746888333 Karel Vodička 535288223 Jan Malý 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 mboxINNER JOIN FETCHmbox.messages • Bez FETCH bychom museli nahrát entity zpráv v Javě pomocí cyklu – problém s výkonností
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)
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
Zdroje • Burke, Bill – Monson-Haefel, Richard; Enterprise Java Beans 3.0; O'Reilly • Goncalves, Antonio; Beginning Java EE 6 Platform With GlassFish 3; APRESS