Sei sulla pagina 1di 9

JJ n.

5 novembre-febbraio 2008

JPA: Java Persistence API


di Fabio Staro

parte 2

La specica JPA fornisce uno standard per la persistenza dei dati in Java, semplicando ` radicalmente la precedente tecnologia degli EJB di tipo Entity Bean. Tuttavia JPA non e ` una reingegnerizzazione della precedente tecnologia ma e di fatto una nuova architettura

Fabio Staro ` Dottore in Fisica e Responsabile Tecnico per i progetti Java presso la Direzione Ricerca ed Innovazione di Engineering Ingegneria Informatica S.p.A.

pubblicato su WWW.INFOMEDIA.IT stampa digitale da Lulu Enterprises Inc. stores.lulu.com/infomedia


Infomedia
` Infomedia e limpresa editoriale che da quasi venti anni ha raccolto la voce dei programmatori, dei sistemisti, dei professionisti, degli studenti, dei ricercatori e dei professori dinformatica italiani. Sono pi` di 800 gli autori che hanno realizzato per le teu state Computer Programming, Dev, Login, Visual Basic Journal e Java Journal, molte migliaia di articoli tecnici, presentazioni di prodotti, tecnologie, protocolli, strumenti di lavoro, tecniche di sviluppo e semplici trucchi e stratagemmi. Oltre 6 milioni di copie distribuite, trentamila pagine stampate, fanno di questa impresa la pi` grande ed u inuente realt` delleditoria specializzata nel campo della a programmazione e della sistemistica. In tutti questi anni le riviste Infomedia hanno vissuto della passione di quanti vedono nella programmazione non solo la propria professione ma unattivit` vitale e un vero a divertimento. ` Nel 2009, Infomedia e cambiata radicalmente adottando ` un nuovo modello aziendale ed editoriale e si e organizzata attorno ad una idea di Impresa Sociale di Comunit` , a partecipata da programmatori e sistemisti, separando le attivit` di gestione dellinformazione gestite da un board a comunitario professionale e quelle di produzione gesti` te da una impresa strumentale. Questo assetto e in linea con le migliori esperienze internazionali e rende Infomedia ancora di pi` parte della Comunit` nazionale degli u a sviluppatori di software. ` Infomedia e media-partner di manifestazioni ed eventi in ambito informatico, collabora con molti dei pi` imporu tanti editori informatici italiani come partner editoriale e fornitore di servizi di localizzazione in italiano di testi in lingua inglese.

Limpaginazione automatica di questa rivista e realizzata al ` 100% con strumenti Open Source usando OpenOffice, Emacs, BHL, LaTeX, Gimp, Inkscape e i linguaggi Lisp, Python e BASH

For copyright information about the contents of Java Journal, please see the section Copyright at the end of each article if exists, otherwise ask authors. Infomedia contents is 2008 Infomedia and released as Creative Commons 2.5 BY-NC-ND. Turing Club content is 2008 Turing Club released as Creative Commons 2.5 BY-ND. Le informazioni di copyright sul contenuto di Java Journal sono riportate nella sezione Copyright alla ne di ciascun articolo o vanno richieste direttamente agli autori. Il contenuto Infomedia e 2008 Infomedia e rila` sciato con Licenza Creative Commons 2.5 BY-NC-ND. Il contenuto Turing Club e 2008 Turing Club e rilasciato ` con Licenza Creative Commons 2.5 BY-ND. Si applicano tutte le norme di tutela dei marchi e dei segni distintivi. ` E in ogni caso ammessa la riproduzione parziale o totale dei testi e delle immagini per scopo didattico purch e vengano integralmente citati gli autori e la completa identicazione della testata. Manoscritti e foto originali, anche se non pubblicati, non si restituiscono. Contenuto pubblicitario inferiore al 45%. La biograa dellautore riportata nellarticolo e sul sito www.infomedia.it e di norma quella disponibi` le nella stampa dellarticolo o aggiornata a cura dellautore stesso. Per aggiornarla scrivere a info@infomedia.it o farlo in autonomia allindirizzo http://mags.programmers.net/moduli/biograa

focus

JAVA Journal

JPA: Java Persistence API seconda parte


La specifica JPA fornisce uno standard per la persistenza dei dati in Java, semplificando radicalmente la precedente tecnologia degli EJB di tipo Entity Bean. Tuttavia JPA non una reingegnerizzazione della precedente tecnologia ma di fatto una nuova architettura
>> di Fabio Staro (fstaro@javajournal.it)

el precedente articolo su JPA (acronimo di Java Persistence Api) [1] abbiamo introdotto le caratteristiche base della specifica ed abbiamo approfondito la gestione delle relazioni tra le entit. Nellarticolo risaltava in modo prepotente la radicale semplificazione presente con JPA rispetto alla precedente specifica per la persistenza dei dati in Java: gli Entity Bean versione 2.x. In questo articolo, conclusivo sullargomento, approfondiamo ulteriormente la specifica soffermandoci sulle strategie di mapping per la gestione della ereditariet, un design pattern frequente nel paradigma di sviluppo object-oriented e non presente nel mondo relazionale dei database. Gli esempi riportati realizzano un processo di sviluppo top-down: ossia, partendo dal modello delle classi deriveremo il disegno delle tabelle. Gli esempi sono stati verificati con lapplication server JBoss versione 5.0 [2], con il database MySQL versione 5.0.27 [3] e con il provider JPA Hibernate [4].

Tra le classi Prodotto e Autore presente una relazione molti a molti bidirezionale. E tra le classi Autore ed Indirizzo presente una relazione uno a uno unidirezionale. La specifica JPA, per supportare in un database relazionale il concetto di ereditariet, offre varie strategie di mapping. Queste sono specificate nella enumerazione javax.persistence.InheritanceType: SINGLE_TABLE; JOINED; TABLE_PER_CLASS;

In questo articolo analizzeremo le prime due strategie per il mapping delle entit tralasciando la strategia TABLE_PER_CLASS in quanto il suo supporto da parte dei provider JPA non obbligatorio nella attuale versione della specifica.

La strategia SINGLE_TABLE Iniziamo con lapprofondire la strategia di mapping SINGLE_TABLE. Questa la strategia di default, dove una sola tabella usata per rappresentare lintera gerarchia delle classi. Una colonna della tabella, assumendo valori differenti in base al tipo Java rappresentato dal record, usata come discriminante per distinguere tra le sottoclassi della gerarchia. Di seguito riportiamo uno stralcio del codice della classe Prodotto:

Strategie per lereditariet Gli esempi che desideriamo realizzare sono volutamente semplificati, al fine di approfondire lAPI e larchitettura JPA eliminando le complessit applicative legate ad un particolare dominio di interesse. Osservando il diagramma delle classi riportato in Figura 1 possiamo notare la semplice gerarchia presente tra le classi: Prodotto, Libro, Video, DVD e VHS. In particolare, la classe astratta Prodotto la root class della gerarchia e le classi Libro e Video la estendono direttamente. La classe Video a sua volta astratta ed estesa dalle classi concrete DVD e VHS.

@Entity(name=Prodotto_Single) @Table(name=PRODOTTO_SINGLE) @Inheritance(strategy=InheritanceType.SINGLE _TABLE)

38

n.5 - novembre/febbraio 2008

JAVA Journal

focus

FIGURA 1

Il diagramma delle classi

@DiscriminatorColumn(name=DISC, discriminatorType=DiscriminatorType.STRING) public abstract class Prodotto { ... @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String titolo; private Date annoProduzione; @ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, targetEntity=Autore.class) private Set<Autore> autori = null; ... }

@DiscriminatorValue(LIBRO) public class Libro extends Prodotto { ... private int numeroPagine; private boolean edizioneEconomica; ... }

Ecco uno stralcio del codice della classe Video,


@Entity(name=Video_Single) public abstract class Video extends Prodotto { ... private boolean colore; ... }

Osservando il codice della classe Prodotto possibile notare luso delle annotazioni @Inheritance e @DiscriminatorColumn. Attraverso lannotazione @Inheritance possibile specificare la strategia di mapping, nellesempio SINGLE_TABLE. Lannotazione @DiscriminatorColumn consente di specificare il nome, nellesempio DISC, e il tipo della colonna che funge da discriminante nel distinguere le sottoclassi della catena gerarchica. Di seguito riportiamo i frammenti di codice significativi per le altre classi della gerarchia. Iniziamo con uno stralcio del codice sorgente della classe Libro:
@Entity(name=Libro_Single)

e della classe VHS,


@Entity(name=VHS_Single) @DiscriminatorValue(VHS) public class VHS extends Video { ... private String tipoNastro = null; ... }

n.5 - novembre/febbraio 2008

39

focus

JAVA Journal
<persistence> <persistence-unit name=GestioneBiblioteca> <jta-data-source>java:/theDataSource</jta-data-source> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>it.articolo.jpa2.Prodotto</class> <class>it.articolo.jpa2.Libro</class> <class>it.articolo.jpa2.Video</class> <class>it.articolo.jpa2.VHS</class> <class>it.articolo.jpa2.DVD</class> <class>it.articolo.jpa2.Autore</class> <class>it.articolo.jpa2.Indirizzo</class> <exclude-unlisted-classes/> <properties> <property name=hibernate.show_sql value=true/> <property name=hibernate.format_sql value=true/> <property name=hibernate.hbm2ddl.auto value=create/> </properties> </persistence-unit> </persistence>

LISTATO 1 Il file persistence.xml e, per concludere, della classe DVD:


@Entity(name=DVD_Single) @DiscriminatorValue(DVD) public class DVD extends Video { ... private boolean contenutiSpeciali; ... }

Osservando la Figura 2 possiamo notare come la strategia SINGLE_TABLE abbia effettivamente portato alla generazione di una singola tabella, nellesempio la tabella PRODOTTO_SINGLE, le cui colonne sono tutti gli attributi delle classi costituenti la gerarchia, pi la colonna discriminante dichiarata attraverso lannotazione @DiscriminatorColumn, nellesempio la colonna DISC. Osserviamo nel dettaglio la struttura della tabella PRODOTTO_SINGLE. Di seguito riportiamo il comando DDL (Data Defination Language) della tabella:
CREATE TABLE PRODOTTO_SINGLE ( DISC varchar(31) NOT NULL, id int(11) NOT NULL auto_increment, titolo varchar(255), annoProduzione datetime, numeroPagine int(11), edizioneEconomica bit(1), colore bit(1), tipoNastro varchar(255), contenutiSpeciali bit(1), PRIMARY KEY (id) )

Osservando il codice sopra riportato possibile notare come, al variare delle classi, varia il valore della colonna discriminante (nellesempio la colonna DISC). Il valore che assume in base al tipo della classe specificato attraverso lannotazione @DiscriminatorValue. In particolare, la colonna DISC assume il valore LIBRO in presenza di un record che rappresenta un oggetto della classe Libro e, viceversa, assume il valore VHS in presenza di un video del tipo VHS ed il valore DVD in presenza di un record che rappresenta un oggetto DVD. Dopo aver definito il modello ad oggetti e dopo aver dichiarato la strategia di mapping per lereditariet, deriviamo la struttura delle tabelle del database (processo di sviluppo top-down). Il provider JPA che usiamo Hibernate il quale grazie alla propriet:
hibernate.hbm2ddl.auto

impostata al valore create consente di derivare le tabelle del database partendo dalle classi opportunamente annotate. Il Listato 1 riporta il sorgente del file persistence.xml. Il risultato del deploy delle classi entity in JBoss la creazione delle tabelle per il database MySql, riportate in Figura 2. FIGURA 2
Il diagramma ER (strategia di mapping SINGLE_TABLE)

40

n.5 - novembre/febbraio 2008

JAVA Journal

focus

FIGURA 3

Il diagramma ER (strategia di mapping JOINED)

A parte la colonna DISC e la colonna ID che la chiave primaria, tutte le altre colonne della tabella possono assumere il valore NULL. Questo necessario, in quanto un record della tabella pu rappresentare una qualsiasi classe presente nella gerarchia. Se, per esempio, avessimo mappato lattributo contenutiSpeciali della classe DVD su una colonna dichiarata come NOT NULL sarebbe stato impossibile persistere un oggetto delle classi Libro e VHS

Considerazioni preliminari sulle strategie di mapping Quale strategia di mapping applicare ad una gerarchia di classi? La risposta a questa domanda non semplice, in quanto varia in funzione del risultato che si desidera ottenere: per esempio, prestazioni adeguate o maggiore flessibilit durante le fasi di design e/o deployment. Di seguito cercheremo di delineare alcune linee guida, ben consci che tali indicazioni sono preliminari e che necessitano di una sperimentazione sul campo, specifica al proprio contesto.

La strategia JOINED Analizziamo ora la strategia di mapping di tipo JOINED. A livello di codice Java le classi Prodotto, Libro, Video, VHS e DVD non variano, a parte il valore assegnato alla annotazione @Inheritance. Di seguito uno stralcio del sorgente delle classe Prodotto e Libro:
@Entity(name=Prodotto_Joined) @Table(name=PRODOTTO_JOINED) @Inheritance(strategy=InheritanceType.JOINED) public abstract class Prodotto {...} @Entity(name=LIBRO_JOINED) public class Libro extends Prodotto {...}

Applicazione della strategia SINGLE_TABLE La strategia di mapping SINGLE_TABLE consigliata in presenza di una gerarchia stabile e sostanzialmente semplice e poco profonda. Infatti aggiungere una nuova classe alla gerarchia o aggiungere nuovi attributi a qualche classe preesistente nella gerarchia porta alla creazione di nuove colonne nella tabella di mapping. Pertanto una gerarchia molto estesa pu condurre alla generazione di una tabella con un numero di colonne elevato con la conseguenza di un impatto negativo sul layout della tabella e del database in generale. Sempre in relazione al layout della tabella di mapping opportuno ricordare che le colonne della tabella mappate sugli attributi delle classi della gerarchia devono poter assumere il valore NULL. Inoltre, se per qualche motivo vi la necessit di mappare uno o pi attributi in colonne di tipo LOB pu essere necessario mappare lentity class non pi su una sola tabella ma su pi tabelle attraverso lannotazione @SecondaryTable. Relativamente alle prestazioni, poich generalmente si in presenza di una singola tabella, le operazioni di ricerca sui diversi tipi della gerarchia o su uno specifico tipo risultano efficienti, non essendo richieste operazioni di JOIN tra tabelle.

La struttura delle tabelle che deriva dal modello delle classi riportata in Figura 3. Per ogni entit della gerarchia generata una tabella le cui colonne sono solo gli attributi esplicitamente dichiarati nella classe. La root class della gerarchia mappata su una root table (in Figura 3 la tabella PRODOTTO_JOINED) nella quale definita la chiave primaria poi usata in tutte le tabelle della gerarchia. Ogni tabella nella gerarchia definisce una chiave primaria uguale alla chiave primaria della root table e definisce una foreign key (chiave esterna) verso la chiave primaria della root table.

n.5 - novembre/febbraio 2008

41

focus

JAVA Journal
Applicazione della strategia JOINED La strategia di mapping di tipo JOINED offre una buona flessibilit durante le fasi di design e di deployment. Infatti, laggiunta o la rimozione di uno o pi attributi ad una classe presente nella gerarchia coinvolge nella modifica solo la tabella che specificatamente rappresenta la classe; mentre lintroduzione di una nuova classe nella gerarchia porta semplicemente alla creazione di una nuova tabella nello schema. Relativamente alle prestazioni, una operazione di ricerca tra le entit della gerarchia necessiter di una o pi operazioni di JOIN anche in funzione della profondit della gerarchia. Pertanto la presenza di un numero elevato di sottoclassi pu avere un impatto negativo sulle prestazioni. Una API per le query con JPA La specifica JPA definisce un linguaggio per eseguire le query sulle entit ed il loro stato persistente. Il linguaggio consente allo sviluppatore di specificare la semantica di una query in modo portabile ed indipendente dallo specifico database presente nella propria infrastruttura tecnologica. Con JPA si in presenza di una radicale estensione del linguaggio EJB QL definito nella precedente specifica per gli EJB di tipo Entity Bean versione 2.1 [5]. Nel precedente articolo su JPA [1] abbiamo osservato come attraverso loggetto EntityManager possibile fare semplici operazioni di ricerca attraverso il metodo find(). La firma del metodo :
public <T> primaryKey); T find(Class<T> entityClass, Object

in JPA. Infatti, il linguaggio object-oriented, usando nella sua sintassi le entity class e le regole di navigazione definite tra le entit, ed indipendente dal database. Al contrario, il linguaggio SQL, pur esistendo uno standard, di fatto coniugato in diversi dialetti caratteristici di ogni database che non ne garantiscono la portabilit (vendor lock-in). Per ottenere una istanza delloggetto Query possibile invocare sulloggetto EntityManger o il metodo createQuery() o il metodo createNativeQuery(). Il primo metodo usa il linguaggio EJB QL per la definizione dello statement mentre il secondo metodo usa il linguaggio SQL. Per esempio, con riferimento alla Figura 2, per ottenere tutti i prodotti possibile scrivere:
public List<Prodotto> getProdotti() { Query query = entityManager.createQuery(SELECT o FROM Prodotto_Single o); return query.getResultList(); }

Lespressione che rappresenta lo statement di una query pu essere ricavata a runtime, ossia durante lesecuzione del programma, come di fatto accade nellesempio precedente; o pu essere dichiarata in un file di configurazione della applicazione. Nel primo caso si in presenza di una query dinamica, nel secondo di una query statica o di una named query. Le query statiche sono dichiarate attraverso la annotazione @NamedQuery. Per esempio, la query precedente pu divenire una named query dichiarandola come annotazione del sorgente della classe Prodotto:
@Entity(name=Prodotto_Single) ... @NamedQuery(name = Prodotto.findAll, query = SELECT o FROM Prodotto_Single o) public abstract class Prodotto implements Serializable { ... }

Il metodo accetta come parametro di input il tipo della entity class di cui tornarne una istanza ed un oggetto che rappresenta la chiave primaria e restituisce listanza della entity class di data chiave primaria. Il metodo pratico e allo stesso tempo semplice. Tuttavia nei progetti necessario, la maggior parte delle volte, eseguire query complesse la cui esecuzione restituisce, eseguendo operazioni di JOIN e condizioni di WHERE articolate, una o pi istanze di entity class. In questi casi necessario usare un oggetto di tipo Query, definito nel package javax.persistence e la sintassi estesa del linguaggio EJB QL. I passi essenziali per creare un oggetto Query ed eseguire una query sono schematizzati di seguito: Recuperare dallEntity Manager una istanza della classe javax.persistence.Query; Impostare i parametri necessari allesecuzione della query; Eseguire effettivamente la query.

Per usare una named query il metodo precedente diviene:


public List<Prodotto> getProdotti() { Query query = entityManager.createNamedQuery( Prodotto.findAll); return query.getResultList(); }

Come si detto in precedenza, le query possono essere scritte attraverso il linguaggio EJB QL. Tuttavia anche possibile usare direttamente il linguaggio SQL ed in tal caso si in presenza di query scritte in linguaggio nativo (indicate, infatti, con il termine native query nella specifica). Il linguaggio EJB QL, sintatticamente molto simile al linguaggio SQL, la via preferenziale per scrivere le query

Ovviamente possibile dichiarare pi di una named query come annotazione di una entity class. In tal caso necessario usare lannotazione @NamedQueries. Prima di terminare opportuno accennare ai named parameters attraverso i quali possibile specificare le condizioni di WHERE. Per esempio se vogliamo ricercare i prodotti che hanno un titolo particolare possiamo definire la named query

42

n.5 - novembre/febbraio 2008

JAVA Journal
come segue:
@NamedQuery(name = Prodotto.findByTitolo, query = SELECT o FROM Prodotto_Single o WHERE o.titolo = :TITOLO) @TransactionAttribute( TransactionAttributeType.REQUIRES_NEW) public void bulkUpdate(String entityName) { String dOperation = UPDATE +entityName+ t SET t.annoProduzione = :ANNO_PRODUZIONE; Query q = entityManager.createQuery(dOperation); q.setParameter(ANNO_PRODUZIONE, null); q.executeUpdate(); } @TransactionAttribute( TransactionAttributeType.REQUIRES_NEW) public void bulkDelete(String entityName) { Query q = entityManager.createQuery( DELETE FROM +entityName); q.executeUpdate(); }

focus

ed un metodo che la usa:


public List<Prodotto> getProdottiByTitolo(String titolo) { Query query = entityManager.createNamedQuery( Prodotto.findByTitolo); query.setParameter(TITOLO, titolo); return query.getResultList(); }

EJB-QL: nuove caratteristiche In precedenza abbiamo osservato come il linguaggio per eseguire le query definito nella specifica JPA sia una estensione del linguaggio EJB QL. In particolare, introduce varie migliorie che di seguito accenniamo: Aggiornamenti e cancellazioni massive; Operazioni di JOIN; Parole chiave GROUP BY e HAVING; Projection; Subquery. In particolare, con riferimento alla Figura 2, il metodo bulkUpdate() imposta il valore della colonna anno di produzione presente nella tabella PRODOTTO_SINGLE al valore null; mentre il metodo bulkDelete() elimina tutti i record rappresentati da una entity class. Osserviamo che se si invocato i metodi bulkUpdate() e bulkDelete() passando come parametro di input il valore Libro_Single, ossia il nome della entity class Libro, sono aggiornati ed eliminati i record relativi ad un libro; viceversa, se si invocano i due metodi passando come parametro di input il valore Prodotto_Single, ossia il nome della entity class Prodotto (la root class della gerarchia), sono aggiornati ed eliminati tutti i record relativi ad un libro, ad un video di tipo DVD e ad un video di tipo VHS.

Operazioni massive Per aggiornamenti e cancellazioni massive indichiamo una singola operazione il cui risultato leliminazione o aggiornamento di un numero, anche elevato, di entit (in inglese i termini per indicare queste caratteristiche sono bulk update e bulk delete). Quando si esegue una operazione di cancellazione o di aggiornamento massivo valgono le seguenti regole: Loperazione massiva si applica allentit sorgente della bulk operation e a tutte le sottoclassi di questa; Loperazione non si propaga alle entit relazionate con lentit sorgente della bulk operation; Il persistence context non sincronizzato con il risultato della operazione.

Operazioni di JOIN Analizziamo ora il supporto introdotto in JPA per la gestione delle operazioni di JOIN. Con JPA possiamo avere i seguenti tipi di JOIN: JOIN; LEFT JOIN; FETCH JOIN.

Per esempio, sempre con riferimento alla Figura 2, se volessimo trovare tutti i prodotti che hanno associato almeno un autore potremmo scrivere la JOIN:
@NamedQuery(name=prodottiByAutoreJOIN, query=SELECT o FROM Prodotto_Single o JOIN o.autori)

Lultima tra le regole sopra elencate merita una riflessione. Poich il persistence context non si sincronizza con il risultato di una operazione massiva necessario che tali operazioni avvengano o allinizio di una transazione o che siano eseguite in una transazione separata. Lo stralcio di codice che segue (due metodi presenti in un EJB di tipo session stateless) mostra un semplice esempio di bulk update e di bulk delete:

Viceversa, per ottenere i prodotti ai quali associato o meno un autore scriveremo la LEFT JOIN:
@NamedQuery(name=prodottiByAutoreLEFT_JOIN, query=SELECT o FROM Prodotto_Single o LEFT JOIN o.autori)

n.5 - novembre/febbraio 2008

43

focus

JAVA Journal
Le FETCH JOIN consentono di caricare le entit correlate specificate in una query, indipendentemente dalla politica di loading specificata nella definizione della relazione. Ricordiamo che in JPA, nella definizione di una relazione, la politica di caricamento pu assumere i valori: EAGER e LAZY (Per ulteriori informazioni si veda [1]). La modalit di caricamento EAGER generalmente meno efficiente, in quanto porta a caricare in memoria lintera mappa delle relazioni; viceversa, la modalit di caricamento LAZY indica che le entit correlate sono caricate solo quando necessario (purch vi sia un persistence context attivo). Ad esempio (sempre con riferimento alla Figura 2), se tra le entit Prodotto e Autore la relazione molti a molti fosse caratterizzata da una modalit di caricamento LAZY e volessimo eseguire una query il cui risultato siano i prodotti con valorizzato lelenco di autori ad essi relazionati potremmo scrivere:
@NamedQuery(name=prodottiByAutoreFETCH_JOIN, query=SELECT o FROM Prodotto_Single o JOIN FETCH o.autori)

Subquery Concludiamo questa panoramica sulle nuove caratteristiche introdotte nel linguaggio parlando delle subquery. Attraverso una subquery possibile eseguire delle query come parte della condizione di WHERE. Luso delle subquery deve essere ben valutato in quanto pu portare ad un degrado delle prestazioni. Ad esempio, se volessimo recuperare tutti i prodotti che sono stati realizzati da almeno due autori possibile scrivere:
@NamedQuery(name=findWithSubQuery, query=SELECT o FROM Prodotto_Single o WHERE (SELECT count(e) FROM o.autori e) > 0)

Conclusioni Con questo articolo concludiamo la panoramica sulla specifica JPA. Non stato possibile trattare tutte le caratteristiche della persistence API, tuttavia sono evidenti due peculiarit: da un lato la semplicit di JPA come prodotto ORM (Object Relational Mapping) e dallaltro lestrema flessibilit dellAPI con il mapping delle relazioni e della ereditariet. Sar il tempo a dirci se JPA diverr la modalit standard e pi diffusa, tra sviluppatori e architetti del software, per persistere gli oggetti in Java. Tuttavia, per quanto si detto e per la diffusione di Hibernate e TopLink (genitori naturali di JPA), le premesse sono estremamente positive. Riferimenti [1] : JPA (prima parte). Java Journal N. 4, anno I. [2]: http://www.jboss.com/. [3]: http://www.mysql.com/ [4]: http://www.hibernate.org/ [5] : Enterprise JavaBeans, v 2.1. http://java.sun.com/ products/ejb Bibliografia: [MEJ]: Mastering Enterprise JavaBeans 3.0, edito dalla Wiley Publishing, Inc. Autori: Rima Patel Sriganesh, Gerald Brose, Micah Silverman. [BAD]: Beginning EJB 3 Application Development, edito dalla Apress. Autori: Raghu R. Kodali and Jonathan Wetherbee with Peter Zadrozny

Parole chiave GROUP BY e HAVING Nella precedente specifica di EJB QL era assente il supporto per le parole chiave GROUP BY e HAVING di SQL. Nella attuale specifica JPA tale supporto stato introdotto: pertanto possibile scrivere query che specificano raggruppamenti e condizioni tramite queste keyword. Per esempio per ottenere i conteggi del numero di video, sia VHS che DVD, che sono a colori ed in bianco e nero possiamo scrivere:
@NamedQuery(name=contaVideo, query=SELECT o.colore, COUNT(o) FROM Video_Single o GROUP BY o.colore)

Proiezioni Con il termine Projection la specifica indica la possibilit che nel risultato di una query siano presenti solo alcuni attributi di una entit o di un insieme di entit. Si tratta di una ottimizzazione nel caso ad un client non interessi lavorare con la totalit degli attributi di una entit, ma solo con un sottoinsieme. Per esempio, se avessimo necessit di un elenco con solo i titoli e lanno di produzione dei prodotti possiamo scrivere:
@NamedQuery(name=findWithProjection, query=SELECT o.titolo, o.annoProduzione FROM Prodotto_Single o)

Il risultato della query un vettore in cui ogni elemento un array di Object. Nellesempio riportato, ogni array di Object ospitato nel vettore contiene due elementi: il titolo di tipo String e lanno di produzione di tipo Date.

Note Biografiche
Fabio Staro dottore in Fisica Responsabile Tecnico per i progetti Java presso la Direzione Ricerca ed Innovazione di Engineering Ingegneria Informatica S.p.A.

44

n.5 - novembre/febbraio 2008