Sei sulla pagina 1di 10

JJ n.

4 settembre-ottobre 2007

JPA: Java Persistence API


di Fabio Staro

parte 1

Sun Microsystems ha eseguito una radicale rivisitazione della tecnologia di persistenza dei ` dati e la nuova specica, JPA, e una chiara semplicazione che si immette nel solco traccia` to dalle soluzioni per la persistenza piu diffuse, tra cui Hibernate, TopLink della Oracle e JDO.

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 2007 Infomedia and released as Creative Commons 2.5 BY-NC-ND. Turing Club content is 2007 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 2007 Infomedia e rila` sciato con Licenza Creative Commons 2.5 BY-NC-ND. Il contenuto Turing Club e 2007 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

speciale Object/Relational Mapping

JAVA Journal

JPA: Java Persistence API


prima parte
Sun Microsystems ha eseguito una radicale rivisitazione della tecnologia di persistenza dei dati e la nuova specifica, JPA, una chiara semplificazione che si immette nel solco tracciato dalle soluzioni per la persistenza pi diffuse, tra cui Hibernate, TopLink della Oracle e JDO.

>> di Fabio Staro (fstaro@javajournal.it)

li Entity Bean 2.x sono stati la tecnologia ufficiale in ambito Java EE per la persistenza dei dati. Tuttavia la complessit presente nello sviluppo e nel deployment ha fatto preferire a questi alternative pi semplici, flessibili e performanti. Nel precedente numero di Java Journal abbiamo introdotto la specifica degli EJB versione 3.0, e in particolare ci siamo soffermati sugli EJB di tipo session stateless. Abbiamo evidenziato come per i nuovi EJB la Sun abbia eseguito una reingegnerizzazione della tecnologia, apportando s nuove caratteristiche, ma soprattutto introducendo una notevole semplificazione. In questo articolo ci soffermeremo sui nuovi entity bean, evidenziando la radicale differenza architetturale presente tra gli entity 3.0 e le precedenti versioni 2.x e 1.x. Se fino alla versione 2.1 gli entity bean sono a tutti gli effetti degli EJB legati necessariamente ad un container EJB, i nuovi entity, descritti nella spe-

cifica JPA per la persistenza e lobject relational mapping, sono classi Java alle quali pu essere associato un contesto di persistenza sia in un ambiente managed, ossia gestito da un Application Server, sia in un ambiente non managed, ossia Java standard, senza alcun Application Server. Dalla specifica JPA leggiamo esplicitamente: This document is the specification of the Java API for the management of persistence and object/relational mapping with Java EE and Java SE. Questa differenza architetturale caratterizza i nuovi entit, oltre ad una notevole semplificazione nella programmazione e nel deployment e a nuove caratteristiche. In questo primo articolo su JPA definiamo una entity class, il concetto del contesto di persistenza e la gestione delle relazioni. Nel prossimo articolo approfondiremo la gestione dellereditariet ed il supporto alle query statiche e dinamiche. Prima di iniziare, osserviamo che JPA una specifica, e pertanto possono esistere diversi provider che la implementano. Tra questi i pi noti sono Hibernate e TopLink.

e pertanto possono esistere diversi provider che la implementano

JPA una specifica,

Una semplice biblioteca Lapplicazione software che desideriamo realizzare volutamente semplice, al fine di approfondire lAPI e larchitettura JPA, eliminando qualsiasi complessit applicativa legata ad un particolare dominio di interesse. La Figura 1 riporta il diagramma Entit-Relazioni (ER) di un semplice repository per i libri di una biblioteca.

20

n.4 - settembre/ottobre 2007

JAVA Journal

Object/Relational Mapping speciale

FIGURA 1 Diagramma Entit Relazioni Osservando la figura, possiamo notare che le entit principali nel diagramma sono quattro: la tabella CASA_EDITRICE, la tabella INDIRIZZO, la tabella LIBRO, la tabella AUTORE. sione 5.0 [1], con il database MySQL versione 5.0.27 [2] e con il provider JPA Hibernate [3]. Definizione di un entity Un entity, nella accezione della specifica JPA, un POJO (acronimo di Plain Old Java Object), ossia una semplice classe Java (che non deve implementare interfacce particolari o estendere classi di un particolare framework) i cui attributi mappano le colonne di una tabella e, in particolare, una istanza della classe rappresenta un ben preciso record di una tabella (questo perch una classe entity deve dichiarare una primary key). Il mapping tra la classe entity e una tabella semplificato attraverso luso delle annotazioni. Lo stralcio di codice che segue mostra la classe CasaEditrice opportunamente annotata:
@Entity(name=CasaEditriceEntity) @Table(name=CASA_EDITRICE) public class CasaEditrice implements Serializable { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name=id_ce) private int identificativo; private String ragioneSociale; private String telefono; private String fax; private String email; }

Le relazioni che intercorrono tra le entit sono le seguenti: una casa editrice ha un solo indirizzo (relazione 1 a 1) e pu, a sua volta, pubblicare molti libri (relazione 1 a molti); un libro a sua volta appartiene ad una e una sola casa editrice (relazione molti a uno), e pu essere stato scritto da vari autori un autore, a sua volta, pu scrivere diversi libri (relazione molti a molti).

Attraverso un processo di realizzazione del tipo bottom-up, ossia partendo dal disegno del database e derivando da questo il modello delle classi, possibile modellare le entit di dominio ottenendo il diagramma delle classi riportato in Figura 2. Le classi mostrate nella Figura 2 non sono, ovviamente, le uniche classi dellapplicazione, ma rappresentano le classi del modello dati e sono in definitiva le entit che devono essere rese persistenti nel database. Le operazioni di business dellapplicazione sono modellate attraverso degli EJB 3.0 di tipo session stateless. Lesempio riportato stato verificato con lapplication server JBoss ver-

n.4 - settembre/ottobre 2007

21

speciale Object/Relational Mapping

JAVA Journal

FIGURA 2 Il diagramma delle classi

Osserviamo in dettaglio il codice riportato. Attraverso lannotazione @Entity, presente nel package javax.persistence informiamo il provider dei servizi JPA che la classe CasaEditrice una classe entity. Lattributo facoltativo name consente di specificare un nome attraverso il quale possibile referenziare la classe entity nelle query. Se lattributo name non specificato assume il valore di default, che il nome non qualificato della classe. Attraverso lannotazione @Table possiamo informare il provider dei servizi JPA su quale tabella presente nel database relazionale mappata dalla entity class (notiamo che possibile specificare oltre allattributo name, anche gli attributi schema e catalog per meglio identificare la tabella). Lannotazione @Column consente di mappare un attributo della classe su una colonna della tabella. Nel codice precedente lattributo identificativo della classe CasaEditrice mappato sulla colonna id_ce della tabella CASA_EDITRICE. importante sottolineare che se non avessimo specificato la annotazione @Column, come stato fatto ad esempio per gli attributi ragioneSociale, telefono, fax ed email, si ha la mappatura automatica dellattributo di classe su una colonna omonima della tabella (un esempio di configuration by exception). In effetti, per indicare al provider dei servizi JPA che un attributo di una entity class non deve essere reso persistente questo deve essere annotato con lannotazione @Transient. Precedentemente abbiamo evidenziato come una istanza di una entity class rappresenti un preciso record di una ta-

bella. Pertanto una entity class deve avere una primary key. Nel codice della classe CasaEditrice lattributo identificativo la chiave primaria dichiarata ed identificata attraverso lannotazione @Id. In casi complessi, la chiave primaria di una entity class pu essere un intero oggetto. JPA attraverso lannotazione @IdClass consente di dichiarare una classe come chiave primaria. Lultima annotazione nel codice precedente lannotazione @GeneratedValue. Attraverso questa annotazione possibile definire la regola di generazione per una chiave primaria. Per esempio, avendo scritto:
strategy=GenerationType.AUTO

il provider JPA assume che la regola di generazione del valore della chiave primaria dipenda dal database utilizzato. Ad esempio, con il database MySQL una strategia di generazione impostata al valore AUTO indica che la colonna sulla tabella del tipo AUTO_INCREMENT. Altri possibili valori presenti nella enumerazione GenerationType sono: SEQUENCE, IDENTITY, TABLE.

I valori SEQUENCE e IDENTITY indicano luso di una sequence nel database o di una colonna identit come strategia di generazione della chiave primaria, mentre il valo-

22

n.4 - settembre/ottobre 2007

JAVA Journal
re TABLE indica che il provider JPA deve assegnare valori univoci usando una tabella del database.

Object/Relational Mapping speciale

Il Persistence Context La logica di business della applicazione di esempio modellata attraverso EJB 3.0 di tipo session stateless. Per esempio, lEJB GestoreCasaEditriceBean ha una serie di metodi per la gestione di una casa editrice. Di seguito riportiamo uno stralcio del codice:
@Stateless (name=CasaEditrice) @TransactionManagement(TransactionManagementType. CONTAINER) public class GestoreCasaEditriceBean implements GestoreCasaEditrice { @PersistenceContext(type=PersistenceContextType.TRANSACTION,unitName=GestioneBiblioteca) private EntityManager manager = null; public boolean inserisci(CasaEditrice ce) { try { manager.persist(ce); } catch(Exception e) { return false; } return true; } public CasaEditrice getCasaEditrice(int identificativo) { return manager.find(CasaEditrice.class, identificativo); } }

sincronizzazione che avviene al commit della transazione. In effetti possibile affermare che listanza della entity class nello stato managed (pi avanti dettaglieremo maggiormente il ciclo di vita di una entity class). Listanza rimane nello stato managed fino a quando non termina il persistence context o fino a quando listanza non esplicitamente rimossa. Il persistence context associato ad un EntityManager pu essere di due tipi (dichiarati nella enumerazione PersitenceContextType): TRANSACTION; EXTENDED;

Un persistence context di tipo TRANSACTION termina quando si conclude la transazione allinterno della quale sono eseguite le operazioni. Da quel momento in poi tutte le istanze delle entity class non sono pi nello stato managed, e pertanto non vi sincronizzazione tra le modifiche che avvengono sulla istanza in memoria ed il database. Un persistence context di tipo EXTENDED termina quando viene rimossa dal container listanza dellEJB di tipo stateful allinterno della quale dichiarato. Le istanze delle entity class, in tale contesto, rimangono nello stato managed durante le invocazioni successive dei metodi di uno stateful session EJB.

Ciclo di vita di un entity Il diagramma degli stati riportato in Figura 3 sintetizza il ciclo di vita di un entity. LEntity Manager distingue quattro diversi stati durante la vita di un entity: New; Managed; Detached; Removed.

Osservando il codice sopra riportato osserviamo che le operazioni di persist() (di fatto una operazione di insert sul database) e di find() (operazione di ricerca) sono invocate su un oggetto EntityManager iniettato nel bean GestoreCasaEditriceBean dal container EJB. Lannotazione @PersistenceContext consente di dichiarare il contesto di persistenza (si veda anche pi avanti dove parliamo del deployment dellapplicazione). Il contesto di persistenza la connessione tra le istanze delle entity class che risiedono in memoria e il database sottostante, ed gestito attraverso una nuova API, linterfaccia EntityManager sempre presente nel package javax.persistence. Attraverso il metodo persist() aggiungiamo una istanza di una entity class al persistence context e da quel momento in poi tutte le modifiche che avvengono sullo stato della entity class sono schedulate per la sincronizzazione sul database,

Quando viene creata, una istanza della classe entity si trova nello stato new, ossia listanza presente in memoria ma non associata ad un contesto di persistenza. Pertanto, le variazioni dei valori degli attributi dellistanza non sono sincronizzate con il database. Un entity nello stato new, dopo linvocazione sullEntity Manager di una operazione di persist(), transita nello stato managed e diviene associata ad un contesto di persistenza, avendo una ben precisa identit di persistenza determinata dalla corrispondente chiave primaria. In questo stato, le variazioni dei valori degli attributi dellistanza sono sincronizzate con il database quando la transazione sottoposta al commit o quando il processo di sincronizzazione viene richiesto direttamente attraverso il comando flush(). Unistanza nello stato managed transita nello stato detached quando termina il contesto di persistenza. Nello stato detached listanza ha ancora una identit di persistenza ma, non essendo pi associata con un contesto di persistenza, non sincronizza variazioni dei suoi attributi con il database. Infine, una istanza della entity class, a fronte di una operazione di remove(), transita dallo stato managed allo stato removed. In questo stato listanza ancora associata ad un contesto di persistenza, ma viene schedulata unoperazione di cancellazione sul database per il record

n.4 - settembre/ottobre 2007

23

speciale Object/Relational Mapping

JAVA Journal

FIGURA 3 Ciclo di vita di un entity da questa rappresentato. Di seguito riportiamo i metodi principali presenti nellinterfaccia dellEntity Manager, direttamente inerenti al ciclo di vita di un entity:
public interface EntityManager { // Fa transitare unistanza nello stato managed e persistente public void persist(Object entity); // Esegue il merge dello stato di un entity in un contesto di persistenza. public <T> T merge(T entity); // Rimuove unistanza dal database public void remove(Object entity); // Controlla se un dato entity presente nel contesto di persistenza corrente public boolean contains(Object entity); }

solo record in relazione con un altro record. Nel modello dei dati dellesempio la relazione che esiste tra una casa editrice e il suo indirizzo; Uno a molti: la relazione indica che un particolare record in relazione con molti altri record. Nel modello dei dati dellesempio la relazione che intercorre tra una casa editrice e i libri da questa pubblicati. Infatti, una casa editrice pubblica molti libri; Molti a uno: la relazione indica che molti record sono in relazione con un solo particolare record. Nel modello dei dati dellesempio la relazione tra i libri e la casa editrice che li pubblica; Molti a molti: la relazione indica che molti record sono in relazione con molti altri record. Nel modello dei dati dellesempio la relazione che esiste tra un libro e i suoi autori. Infatti, un libro pu essere scritto da pi autori, e un autore, viceversa, pu scrivere vari libri.

La gestione delle relazioni Il supporto per la gestione delle relazioni presente fin dalla specifica 2.0 degli EJB di tipo Entity. Con gli EJB 3.0 la gestione delle relazioni stata notevolmente semplificata attraverso luso delle annotazioni. I tipi di relazione che possibile modellare tra le entity class sono: Uno a uno: la relazione indica che vi esattamente un

Inoltre, le relazioni possono essere unidirezionali o bidirezionali. Nel caso unidirezionale solo lentit proprietaria della relazione a conoscenza della relazione, mentre in una relazione bidirezionale entrambe le entit ne sono a conoscenza. Ad esempio, nel diagramma delle classi riportato in Figura 2 la relazione che esiste tra una casa editrice e il suo indirizzo stata modellata come unidirezionale, e pertanto, data una casa editrice possibile ricavare il suo indirizzo e non il viceversa; mentre la relazione tra una casa editrice e i libri da questa pubblicati modellata come bidirezionale in quanto, data una casa editrice, possibile ricavare i libri da questa pubblicati, e dato un libro, possibile conoscere la casa editrice che lo ha pubblicato. Iniziamo con lanalizzare uno stralcio del codice sorgente della classe CasaEditrice dove presente la relazione uno a

24

n.4 - settembre/ottobre 2007

JAVA Journal
uno unidirezionale con la classe Indirizzo:
@Entity(name=CasaEditriceEntity) @Table(name=CASA_EDITRICE) public class CasaEditrice implements Serializable { @OneToOne(cascade=CascadeType.ALL,fetch=FetchT ype.EAGER,targetEntity=Indirizzo.class) @JoinColumn(name=indirizzo, referencedColumn Name=id_ indirizzo) private Indirizzo indirizzo = null; public Indirizzo getIndirizzo() { return indirizzo; } public void setIndirizzo(Indirizzo indirizzo) { this.indirizzo = indirizzo; } }

Object/Relational Mapping speciale

lelemento cascade per default non vi alcuna propagazione delle operazioni di persistenza tra le entit correlate. Lelemento fetch nella annotazione @OneToOne pu assumere i valori presenti nella enumerazione javax.persistence.FetchTy pe che sono:

Una entity class deve


avere una primary key

La relazione uno a uno che esiste tra una casa editrice e il suo indirizzo dichiarata attraverso lannotazione @OneToOne. Prima di esaminare nel dettaglio gli elementi cascade, fetch e targetEntity valorizzati nella dichiarazione della annotazione, analizziamo lannotazione @JoinColumn. Questa annotazione, consente di definire la colonna che funge da foreign key (ossia da chiave esterna). In particolare, attraverso lelemento name dellannotazione possibile specificare il nome della colonna che la foreign key, mentre con lelemento referencedColumnName si specifica il nome della colonna (presente nella tabella correlata) referenziata dalla foreign key. Lelemento cascade presente nellannotazione @OneToOne pu assumere i valori definiti nella enumerazione javax.persistence.CascadeType e sono: ALL; PERSIST; MERGE; REMOVE; REFRESH;

EAGER; LAZY;

Specificare
cascade={CascadeType.ALL}

equivalente ad aver specificato


cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE, CascadeType.REFRESH}

Lelemento cascade indica il tipo di operazione che deve essere propagata sulla entit correlata. Ad esempio, se lentit correlata (che nel nostro esempio la classe Indirizzo) assume il valore PERSIST, questa viene resa persistente sul database nel momento in cui si invoca il metodo persist() dellEntity Manager per lentit owner della relazione (nel nostro caso la classe CasaEditrice). Se non si specifica

In una relazione uno a uno, il valore di default dellelemento fetch EAGER, mentre sar LAZY nelle relazioni uno a molti e molti a molti. Il valore EAGER per lelemento fetch indica che le entit correlate vengono caricate assieme (una sorta di caricamento anticipato); viceversa, il valore LAZY indica che le entit correlate vengono caricate solo quando necessario (una forma di caricamento differito). La scelta della modalit di caricamento delle entit ha un impatto rilevante sulle prestazioni dellapplicazione. La modalit di caricamento EAGER generalmente meno efficiente, in quanto comporta il caricamento in memoria dellintera mappa delle relazioni. Ad esempio, osserviamo il diagramma delle classi e il diagramma Entit/Relazioni del nostro esempio: se per tutte le entit correlate la politica di caricamento fosse impostata al valore EAGER, allora una semplice query di ricerca di una casa editrice comporterebbe il caricamento anche dellindirizzo e, soprattutto, di tutti i libri da questa pubblicati; e per ogni libro si avrebbe il caricamento degli autori. Si intuisce facilmente che impostare tutte le relazioni al valore EAGER porta facilmente ad un degrado delle prestazioni! Se si sta operando su un insieme di entit allinterno di un persistence context attivo, come politica di caricamento normalmente pi efficiente il valore LAZY. Inoltre, possibile, attraverso luso delle fetch join (argomento che approfondiremo nel prossimo articolo), personalizzare la modalit di caricamento delle entit con un maggiore livello di granularit (di fatto, caso per caso, attraverso query specifiche). Nello precedente stralcio di codice lannotazione @OneToOne anche caratterizzata dallelemento facoltativo targetEntity. Attraverso questo elemento possibile specificare la classe dellentit correlata, che nel codice riportato la classe Indirizzo. Il pi delle volte questo elemento pu essere omesso, poich la classe dellentit correlata viene ricavata dal provider JPA

n.4 - settembre/ottobre 2007

25

speciale Object/Relational Mapping

JAVA Journal
mappedBy. Attraverso questo elemento indichiamo la propriet owner della relazione, che nellesempio lattributo casaEditrice presente nella classe della entit correlata, la classe Libro. Nella dichiarazione della annotazione @OneToMany omesso lelemento targetType, in quanto, grazie alluso dei generics, possibile dichiarare esplicitamente il tipo dellinsieme di oggetti correlati ad una casa editrice (Collection<Libro>). Per concludere la panoramica sui tipi di relazioni, analizziamo la relazione bidirezionale molti a molti tra le entit Libro e Autore. Di seguito riportato uno stralcio del codice della classe Libro:
@Entity(name=LibroEntity) @Table(name=LIBRO) public class Libro implements Serializable { @ManyToMany(mappedBy=libri, cascade=CascadeType.ALL, fetch=FetchType.EAGER) private Set<Autore> autori = null; public Set<Autore> getAutori() { return autori; } public void addAutore(Autore autore) { if (null==autori) autori=new HashSet<Autore>(); if (!autori.contains(autore)) { autori.add(autore); autore.addLibro(this); } } }

dallanalisi del tipo dellattributo di relazione (nel precedente stralcio di codice, lelemento targetEntity pu essere in effetti omesso). Tuttavia, lelemento targetEntity necessario se, ad esempio, come tipo dellattributo di relazione non si specifica la classe dellentit correlata ma, ad esempio, linterfaccia da questa implementata. La classe CasaEditrice ha una relazione bidirezionale uno a molti con la classe Libro. Di seguito riportiamo uno stralcio del codice sorgente della classe Libro:
@Entity(name=LibroEntity) @Table(name=LIBRO) public class Libro implements Serializable { @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name=casaEditrice, referencedColumnName=id_ce) private CasaEditrice casaEditrice = null; public CasaEditrice getCasaEditrice() { return casaEditrice; } public void setCasaEditrice(CasaEditrice casaEditrice) { this.casaEditrice = casaEditrice; } }

e della classe CasaEditrice:


@Entity(name=CasaEditriceEntity) @Table(name=CASA_EDITRICE) public class CasaEditrice implements Serializable { @OneToMany(mappedBy=casaEditrice, cascade=CascadeType.ALL, fetch=FetchType.EAGER) private Collection<Libro> libri = null; public Collection<Libro> getLibri() { return libri; } public void addLibro(Libro libro) { if (this.getLibri() == null) this.libri = new ArrayList<Libro>(); libro.setCasaEditrice(this); this.getLibri().add(libro); } }

e della classe Autore:


@Entity(name=AutoreEntity) @Table(name=AUTORE) public class Autore implements Serializable { @ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinTable(name=LIBRO_AUTORE, joinColumns={@JoinColumn(name=autore_ id,referencedColumnName=id_autore)}, inverseJoinColumns={@JoinColumn (name=libro_ id, referencedColumnName=id)} private Set<Libro> libri = null; public void addLibro(Libro libro) { if (null == libri) libri=new HashSet<Libro>(); if (!libri.contains(libro)) {

Osserviamo il codice della classe Libro. La relazione molti a uno con la classe CasaEditrice esplicitata attraverso luso dellannotazione @ManyToOne. Poich la relazione tra le due entit bidirezionale, osservando il codice della classe CasaEditrice notiamo, come si pu intuire, la presenza dellannotazione @OneToMany. In questa classe, oltre agli elementi cascade e fetch, dichiarato lelemento

26

n.4 - settembre/ottobre 2007

JAVA Journal

Object/Relational Mapping speciale

Analizziamo i tag XML di una persistence unit:

Il supporto per la
gestione delle relazioni presente fin dalla specifica 2.0 degli EJB di tipo Entity

libri.add(libro); libro.addAutore(this); } } public Collection<Libro> getLibri() { return libri; } }

<description>: un testo opzionale <provider>: nome qualificato della classe del provider, nel nostro caso Hibernate, che implementa la specifica JPA; <transaction-type>: attributo del tag <persistence-unit>. JTA il valore di default altrimenti pu assumere il valore RESOURCE_LOCAL; <jta-data-source>: nome JNDI del datasource; <non-jta-data-source>: nome JNDI del datasource; <mapping-file>: file XML, in alternativa alle annotazioni, dove specificare le regole di mapping per le entity class; <jar-file>: archivio dove cercare le entity class disponibili per la persistence unit; <class>: le classi disponibili per la persistence unit; <exclude-unlisted-classes>: se questo elemento presente solo le entity class o gli archivi definiti con i tag mapping-file, jar-file e class sono disponibili nella persistence unit; <properties>: propriet specifiche del provider JPA.

Conclusioni In questo primo articolo abbiamo trattato i fondamenti della specifica JPA. Nel prossimo articolo parleremo della gestione dellereditariet e delle query statiche e dinamiche.

Riferimenti [1]: http://www.jboss.com/ [2]: http://www.mysql.com/ [3]: http://www.hibernate.org/

La relazione molti a molti esplicitata attraverso luso dellannotazione @ManyToMany. Osserviamo che nella classe Autore attraverso la annotazione @JoinTable possibile specificare la tabella associativa che di fatto realizza la relazione nello schema Entit/Relazioni di Figura 1.

Bibliografia: Il deployment dellapplicazione Le entity class sono raccolte in persistence unit. Una persistence unit una unit logica di entity class, con i metadati per il mapping e le configurazioni specifiche per il database ed il provider JPA. Una persistence unit definita in un file descrittore chiamato persistence.xml che deve essere presente nella cartella META-INF di un archivio jar o di un archivio war o ear. Di seguito riportiamo il file persistence.xml dellesempio della gestione della biblioteca:
<persistence> <persistence-unit name=GestioneBiblioteca> <jta-data-source>java:/theDataSource</jtadata-source> <provider>org.hibernate.ejb.HibernatePersistence </provider> </persistence-unit> </persistence>

[4] R. P. Sriganesh, G. Brose, M. Silverman Mastering Enterprise JavaBeans 3.0, Wiley Publishing, Inc., 2006. [5] R. R. Kodali, J. Wetherbee e P. Zadrozny Beginning EJB 3 Application Development, Apress, 2006.

Note Biografiche
Jacopo Giudici si occupa di applicazioni per il Web, di RFID e di domotica su piattaforme J2ME, J2EE e .NET. Progetta e tiene corsi di formazione aziendali sulla sicurezza delle reti informatiche e sulla programmazione Java per ambienti distribuiti.Ha lavorato per Microsoft, BottegaVerde, CONAD, Confartigianato e ha pubblicato una collana di 6 libri con DeAgostini Scuola sui Sistemi Elettronici-Informatici per il triennio degli istituti tecnici superiori.

n.4 - settembre/ottobre 2007

27