Vous êtes sur la page 1sur 176

4.

1: Couche Persistance EJB3/JPA


Formation Java EE 5 / Spring Par Adel ELJ, Architecte J2EE

Page 2

EJB 3.0

le e p m nc e e Ex f r r
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 3

I.Prsentation de JPA

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 4

EJB 3.0
Java EE 5 (Enterprise Edition) est une plateforme de dveloppement et un ensemble de spcifications pour le dveloppement dapplications dentreprises multi-tiers EJB 3 fait partie de Java EE 5 ; cest une spcification rcente (mai 2006) dun cadre (framework) pour lutilisation de composants mtier rutilisables par des serveurs dapplications Java

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 5

JPA
JPA (Java persistence API) est la partie de la spcification EJB 3.0 qui concerne la persistance des composants dans une base de donnes Relationnelle Peut sappliquer sur toutes les applications Java, mme celles qui sexcutent en dehors dun serveur dapplications

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 6

Solution ORM
Transparente : les classes des entits persistantes sont indiffrentes au mcanisme de persistance Automatique : des appels simples de haut niveau pour grer la persistance, tels que persist(objet) pour rendre un objet persistant ; pas dappel de bas niveau comme avec JDBC

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 7

Fournisseur de persistance
Comme pour JDBC, lutilisation de JPA ncessite un fournisseur de persistance qui implmente les classes et mthodes de lAPI GlassFish, est limplmentation de rfrence de la spcification EJB 3 GlassFish utilise TopLink essentials comme fournisseur de persistance pour JPA (produit Oracle) Dautres implmentations : TopLink, Hibernate Entity Manager, BEA Kodo

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 8

Entits
Les classes dont les instances peuvent tre persistantes sont appeles des entits dans la spcification de JPA Le dveloppeur indique quune classe est une entit en lui associant lannotation @Entity Ne pas oublier dimporter javax.Persistence.Entity dans les classes entits (idem pour toutes les annotations)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 9

Exemple dentit les champs

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 10

Les constructeurs
/** * Constructeur sans paramtre * obligatoire. */ public Departement() { } public Departement(String nom, String lieu) { this.nom = nom; this.lieu = lieu; }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 11

Exemple dentit lidentificateur


@Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 12

Exemple dentit une proprit

public String getNom() { return nom; } public void setNom(String nom) { this.nom = nom; }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 13

Exemple dentit une association


@OneToMany(mappedBy="dept") public Collection<Employe> getEmployes() { return employes; } public void setEmployes(Collection<Employe> emps) { this.employes = emps; }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 14

Configuration de la connexion
Il est ncessaire dindiquer au fournisseur de persistance comment il peut se connecter la base de donnes Les informations doivent tre donnes dans un fichier persistence.xml situ dans un rpertoire META-INF dans le classpath Ce fichier peut aussi comporter dautres informations ; il est tudi en dtails dans la suite du cours

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 15

Exemple (dbut)
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="Employes"> <class>jpa.Departement</class> <class>jpa.Employe</class> <properties> <property name="toplink.jdbc.driver" value="oracle.jdbc.OracleDriver"/> <property name="toplink.jdbc.url" value="jdbc:oracle:thin:@cl.truc.fr:1521:XE"/>

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 16

Exemple (fin)
<property name="toplink.jdbc.user value="toto"/> <property name="toplink.jdbc.password value="xxxxx"/> </properties> </persistence-unit> </persistence>

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 17

Gestionnaire dentits
Classe javax.persistence.EntityManager Le gestionnaire dentits (GE) est linterlocuteur principal pour le dveloppeur Il fournit les mthodes pour grer les entits : les rendre persistantes, les supprimer de la base de donnes, retrouver leurs valeurs dans la base, etc.

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Exemple de code (1) en dehors dun serveur dapplication


Page 18

EntityManagerFactory emf = Persistence. createEntityManagerFactory("employes"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); em.tx.begin(); Dept dept = new Dept("Direction", "Nice"); em.persist(dept); dept.setLieu("Paris"); tx.commit();

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 19

Exemple de code (2)


String queryString = "SELECT e FROM Employe e " + WHERE e.poste = :poste"; Query query = em.createQuery(queryString); query.setParameter("poste", "INGENIEUR"); List<Employe> liste = query.getResultList(); for (Employe e : liste) { System.out.println(e.getNom()); } em.close(); emf.close()

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 20

Contexte de persistance
La mthode persist(objet) de la classe EntityManager rend persistant un objet Lobjet est ajout un contexte de persistance qui est gr par le GE Toute modification apporte un objet du contexte de persistance sera enregistre dans la base de donnes Lensemble des entits gres par un GE sappelle un contexte de persistance

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 21

II. Entits

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 22

Caractristiques
Seules les entits peuvent tre
o o o o

renvoyes par une requte (Query) passes en paramtre dune mthode dun EntityManager ou dun Query le but dune association rfrences dans une requte JPQL

Une classe entit peut utiliser dautres classes pour conserver des tats persistants (MappedSuperclass ou Embedded tudies plus loin)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 23

Conditions pour les classes entits


Elle doit possder un attribut qui reprsente la cl primaire dans la BD (@Id) Une classe entit doit avoir un constructeur sans paramtre protected ou public Elle ne doit pas tre final Aucune mthode ou champ persistant ne doit tre final Si une instance peut tre passe par valeur en paramtre dune mthode comme un objet dtach, elle doit implmenter Serializable

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 24

2 types daccs
Le fournisseur de persistance accdera la valeur dune variable dinstance
o o

soit en accdant directement la variable dinstance soit en passant par ses accesseurs (getter ou setter)

Le type daccs est dtermin par lemplacement des annotations (associes aux variables dinstance ou aux getter)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 25

Accs par proprit


Les accesseurs (setter et getter) doivent tre protected ou public Ils peuvent contenir dautres instructions que le seul code li la valeur de la variable sous-jacente Ces instructions seront excutes par le fournisseur de persistance Si une exception est leve par un accesseur, la transaction est invalide ; les exceptions contrles sont enveloppes par une PersistenceException (non contrle, sous RuntimeException)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 26

Choix du type daccs


Le choix doit tre le mme pour toutes les classes dune hirarchie dhritage (interdit de mlanger les 2 faons) En programmation objet il est conseill dutiliser plutt les accesseurs que les accs directs aux champs (meilleur contrle des valeurs) ; cest aussi le cas avec JPA Rappel : le choix est dtermin par l'emplacement des annotations ; elles sont associes soit aux accesseurs, soit aux variables d'instance ; ne pas mlanger les 2 !
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 27

Cycle de vie dune instance dentit


Linstance peut tre
o nouvelle (new) : elle est cre mais pas

associe un contexte de persistance

o gre (managed) par un gestionnaire de

persistance elle a une identit dans la base de donnes (un objet peut devenir gr par la mthode persist, ou merge dune entit dtache ; un objet gr peut aussi provenir dune requte faite par un gestionnaire dentits ou dune navigation partir dun objet gr)
Adel ELJ (Architecte J2EE)

Esprit 2009/2010

Page 28

Cycle de vie dune instance dentit


o dtache (detached) : elle a une identit dans la

base mais elle nest plus associe un contexte de persistance (une entit peut, par exemple, devenir dtache si le contexte de persistance est vid ou si elle est envoye dans une autre JVM par RMI)

o supprime (removed): elle a une identit dans

la base ; elle est associe un contexte de persistance et ce contexte doit la supprimer de la base de donnes (passe dans cet tat par la mthode remove)
Adel ELJ (Architecte J2EE)

Esprit 2009/2010

Page 29

Cycle de vie dune instance dentit

find query

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 30

Les tables de la base de donnes


Dans les cas simples, une table correspond une classe o le nom de la table est le nom de la classe o les noms des colonnes correspondent aux noms des attributs persistants Par exemple, les donnes de la classe Departement sont enregistres dans la table Departement (ou DEPARTEMENT) dont les colonnes se nomment id, nom, lieu

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 31

Configuration par exception


La configuration des classes entits suppose des valeurs par dfaut Il nest ncessaire dajouter des informations de configuration que si ces valeurs par dfaut ne conviennent pas Par exemple, @Entity suppose que la table qui contient les donnes des instances de la classe a le mme nom que la classe

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 32

Nom de Table
Pour donner la table un autre nom que le nom de la classe, il faut ajouter une annotation @Table Exemple : @Entity @Table(name="AUTRENOM") public class Classe { ... }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 33

Nom de Colonne
Pour donner une colonne de la table un autre nom que le nom de lattribut correspondant, il faut ajouter une annotation @Column Cette annotation peut aussi comporter des attributs pour dfinir plus prcisment la colonne Exemple : @Column(name="AUTRENOM", Updatable=false, length=80) public String getTruc() { ... }
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 34

Classe Embeddable
Les entits persistantes ne sont pas les seules classes persistantes Il existe aussi des classes insres ou incorpores (embedded) dont les donnes nont pas didentit dans la BD mais sont insres dans une des tables associes une entit persistante Elles peuvent tre annotes comme les entits (avec @Column par exemple) Par exemple, une classe Adresse dont les valeurs sont insres dans la table Employe

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 35

Classe Embeddable
Comme les entits, ces classes doivent avoir un constructeur sans paramtre Les types permis pour leurs attributs sont les mmes que les types permis pour les attributs des entits

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 36

Classe Embeddable
@Embeddable @Embeddable public class Adresse { public class Adresse { private int numero; private int numero; private String rue; private String rue; private String ville; private String ville; . . . . . . } } @Entity @Entity public class Employe { public class Employe { @Embedded private Adresse adresse; @Embedded private Adresse adresse; . . . . . .
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 37

Annotation pour numration


Une annotation spciale nest pas ncessaire si un attribut est de type numration si lnumration est sauvegarde dans la BD sous la forme des numros des constantes de lnumration de n) Si on souhaite sauvegarder les constantes sous la forme de la forme dune String qui reprsente le nom de la valeur de lnumration, il faut utiliser lannotation @Enumerated
Exemple: @Enumerated(EnumType.STRING) private TypeEmploye typeEmploye;

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 38

Types temporels
Lorsqu'une classe entit a un attribut de type temporel (Calendar ou Date de java.util), il est obligatoire d'indiquer de quel type temporel est cet attribut par une annotation @Temporal Cette indication permettra au fournisseur de persistance de savoir comment dclarer la colonne correspondante dans la base de donnes : une date (un jour), un temps sur 24 heures (heures, minutes, secondes la milliseconde prs) ou un timeStamp (date + heure la microseconde prs)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 39

Annotation pour les types temporels


3 types temporels dans lnumration TemporalType :
o o o

TemporalType.DATE: une date seule sans heure associe TemporalType.TIME: une heure TemporalType.TIMESTAMP: une date avec heure

Correspondent aux 3 types de SQL ou du paquetage java.sql: Date, Time et Timestamp Exemple: @Temporal(TemporalType.DATE) private Calendar dateEmbauche;

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 40

Tables multiples
Il est possible de sauvegarder une entit sur plusieurs tables Voir @SecondaryTable dans la spcification JPA Cest surtout utile pour les cas o la base de donnes existe dj et ne correspond pas tout fait au modle objet

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 41

Schma relationnel
Dans le cas o le schma relationnel est construit automatiquement partir des annotations, il est possible de prciser des informations sur les tables gnres ou les colonnes de ces tables Par exemple, une contrainte d'unicit, ou "not null", la longueur des colonnes de type varchar, la prcision des nombres virgule, ou mme le texte entier qui permet de dfinir une colonne Voir la spcification JPA pour plus de dtails
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 42

Exemple
Entity Entity @Table(name="PARTICIPATION2", @Table(name="PARTICIPATION2", uniqueConstraints == uniqueConstraints @UniqueConstraint( @UniqueConstraint( columnNames == columnNames {"EMPLOYE_ID", "PROJET_ID"}) {"EMPLOYE_ID", "PROJET_ID"}) )) public class Participation {{ public class Participation ... ... }}
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 43

Types persistants
Les champs des entits peuvent tre d peu prs nimporte quel type : Types primitifs Types String, BigInteger, BigDecimal, classes Enveloppes (Wrapper) des type primitifs (exemp: Integer), Date (des paquetages util et sql), Calendar, Time, Timestamp, et plus gnralement Serializable Enumrations Entits et collections dentits, classes Embeddable
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 44

(Entity Manager) GE

III. Gestionnaire dentits

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 45

Principe de Base
La persistance des entits nest pas transparente Une instance dentit ne devient persistante que lorsque lapplication appelle la mthode approprie du gestionnaire dentit persist ou merge) Cette conception a t voulue par les concepteurs de lAPI par souci de flexibilit et pour permettre un contrle fin sur la persistance des entits

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 46

Unit de persistance
Cest une configuration nomme qui contient les informations ncessaires lutilisation dune base de donnes Elle est associe un ensemble de classes entits

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Configuration dune unit de persistance

Page 47

Les informations sur une unit de persistance sont donnes dans un fichier persistence.xml situ dans un sousrpertoire META-INF dun des rpertoires du rpertoire META dun classpath Voir section Configuration dune unit de persistance dans la suite du cours

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 48

Contexte de persistance (1)


Les entits gres par un gestionnaire dentits forment un contexte de persistance Quand une entit est incluse dans un contexte de persistance (persist ou merge), ltat de lentit est automatiquement sauvegard dans la base au moment du commit de la transaction Proprit importante : dans un contexte de persistance il nexiste pas 2 entits diffrentes qui reprsentent des donnes identiques dans la base
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 49

Contexte de persistance (2)


Un contexte de persistance ne peut appartenir qu une seule unit de persistance Une unit de persistance peut contenir plusieurs contextes de persistance Cest la responsabilit de lapplication de sassurer quune entit nappartient qu un seul contexte de persistance (afin que 2 entits de 2 contextes de persistance diffrents ne puissent correspondre des donnes identiques dans la base de donnes)
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 50

Contexte de persistance - cache


Le contexte de persistance joue le rle de cache et vite ainsi des accs la base Performance Si le code veut rcuprer des donnes (par un find ou un query) qui correspondent une entit du contexte, ce sont les donnes du cache qui sont renvoyes Important : si les donnes de la base ont t modifies (et valides) en parallle dans la base (par exemple en dehors de lapplication), les donnes rcupres ne tiennent pas compte de ces modifications
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 51

Contexte de persistance - cache


Ce fonctionnement peut tre bnfique : o meilleures performances, o isolation lecture rptable sans modifier les paramtres de la base de donnes Mais si modifications effectues en parallle sur les donnes dune entit il est possible de les rcuprer en utilisant la mthode refresh de la classe EntityManager

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 52

Interface EntityManager
Elle reprsente un GE Limplmentation de linterface fournie par le fournisseur de persistance

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 53

Types de GE
GE gr par le container (uniquement disponible dans un serveur dapplications) ; le contexte de persistance peut tre limit une seule transaction (cas dun SLSB) ou plusieurs (cas dun SFSB) GE gr par lapplication (type disponible en dehors dun serveur dapplications) ; le contexte de persistance reste attach au GE pendant toute son existence.

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 54

Cycle de vie dun GE


En dehors dun serveur dapplications, cest lapplication qui dcide de la dure de vie dun GE La mthode createEntityManager() de la classe EntityManagerFactory cr un GE Le GE est supprim avec la mthode close() de la classe EntityManager ; il ne sera plus possible de lutiliser ensuite

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 55

Fabrique de GE
La classe Persistence permet dobtenir une fabrique de gestionnaire dentits par la mthode createEntityManagerFactory 2 variantes surcharges de cette mthode :
o

1 seul paramtre qui donne le nom de lunit de persistance (dfinie dans le fichier persistence.xml) Un 2me paramtre de type Map qui contient des valeurs qui vont craser les proprits par dfaut contenues dans persistence.xml

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 56

A savoir
Une EntityManagerFactory est threadsafe Un EntityManager ne lest pas Crer une EntityManagerFactory est une opration lourde Crer un EntityManager est une opration lgre Il est donc intressant de conserver une EntityManagerFactory entre 2 utilisations
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 57

Mauvaise configuration
Si elle rencontre une mauvaise configuration (dans le fichier persistence.xml, dans les annotations, y compris dans la syntaxe des requtes nommes ou dans les fichiers XML), la mthode Persistence.createEntityManagerFactory ne se terminera pas correctement et lancera une exception

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 58

Mthodes de EntityManager
void persist(Object entit) <T> T merge(T entit) void remove(Object entit) <T> T find(Class<T> classeEntit, Object clPrimaire) <T> T getReference(Class<T> classeEntit, Object clPrimaire) void flush() void setFlushMode(FlushModeType flushMode)
Adel ELJ (Architecte J2EE)

Esprit 2009/2010

Page 59

Mthodes de EntityManager
void lock(Object entit, LockModeType lockMode) void refresh(Object entit) void clear() boolean contains(Object entit) Query createQuery(String requte) Query createNamedQuery(String nom)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 60

Mthodes de EntityManager
Query createNativeQuery(String requte) Query createNativeQuery(String requte, Class classeRsultat) void joinTransaction() void close() boolean isOpen() EntityTransaction getTransaction()

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 61

flush
Toutes les modifications effectues sur les entits du contexte de persistance gres par le GE sont enregistres dans la BD lors dun flush du GE Au moment du flush, le GE tudie ce quil doit faire pour chacune des entits quil gre et il lance les commandes SQL adaptes pour modifier la base de donnes (INSERT, UPDATE ou DELETE)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 62

flush
Un flush est automatiquement effectu au moins chaque commit de la transaction en cours Une exception TransactionRequiredException est leve si la mthode flush est lance en dehors dune transaction

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 63

Flush( vrifier)
Soit X une des entits gre, avec une association de X vers une entit Y Si cette association est note avec cascade=persist ou cascade=all, Y est aussi flushe Sinon, si Y est new ou removed, une exception IllegalStateException sera leve et la transaction est invalide (rollback) ( tester) Sinon, si Y est dtache et X possde lassociation, Y est flushe ; si Y est la propritaire, le comportement est indfini
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 64

Mode de flush
Normalement (mode FlushMode.AUTO) un flush des entits concernes par une requte est effectu avant la requte pour que le rsultat tienne compte des modifications effectues en mmoire sur ces entits Il est possible d'viter ce flush avec la mthode setFlushMode : em.setFlushMode(FlushMode.COMMIT); En ce cas, un flush ne sera lanc qu'avant un commit Il est possible de modifier ce mode pour une seule requte (voir Query)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 65

persist
Une entit nouvelle devient une entit gre Ltat de lentit sera sauvegard dans la BD au prochain flush ou commit Aucune instruction ne sera ncessaire pour faire enregistrer au moment du commit dans la base de donnes les modifications effectues sur lentit par lapplication ; en effet le GE conserve toutes les informations ncessaires sur les entits quil gre
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 66

persist(A) A:une Entit


Si A est nouvelle, elle devient gre Si A tait dj gre, persist est ignore mais lopration persist cascade sur les entits associes si lassociation a lattribut CascadeType.PERSIST Si A est supprime (a t passe en paramtre remove), elle devient gre Si A est dtache, une IllegalArgumentException est lance
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 67

Remove(A)
Si A est gre, elle devient supprime (les donnes correspondantes de la base seront supprimes de la base au moment du flush du contexte de persistance) Ignore si A est nouvelle ou supprime Si A est dtache, une IllegalArgumentException est lance Ne peut tre utilis que dans le contexte dune transaction
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 68

refresh
Le GE peut synchroniser avec la BD une entit quil gre en rafraichissant son tat en mmoire avec les donnes actuellement dans la BD : em.refresh(entite); Les donnes de la BD seront copies dans lentit Utiliser cette mthode pour sassurer que lentit a les mmes donnes que la BD Peut tre utile pour les contextes de persistence de longue dure
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 69

refresh(A)
Ignore si A est nouvelle ou supprime Si A est nouvelle, lopration cascade sur les associations qui ont lattribut CascadeType.REFRESH Si A est dtache, une IllegalArgumentException est lance

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 70

find
La recherche est polymorphe : l'entit rcupre peut tre de la classe passe en paramtre ou d'une sous-classe (renvoie null si aucune entit na lidentificateur pass en paramtre) Exemple : Article p = em.find(Article.class, 128); peut renvoyer un article de n'importe quelle sousclasse de Article (Stylo, Ramette,)
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 71

lock
Le fournisseur de persistance gre les accs concurrents aux donnes de la BD reprsentes par les entits avec une stratgie optimiste (optimistic locking) lock permet de modifier la manire de grer les accs concurrents une entit A Sera tudi plus loin dans la section sur la concurrence

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 72

Entit dtache (1)


Une application distribue sur plusieurs ordinateurs peut utiliser avec profit des entits dtaches Une entit gre par un GE peut tre dtache de son contexte de persistance ; par exemple, si le GE est ferm ou si lentit est transfre sur une autre machine en dehors de la porte du GE

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 73

Entit dtache (2)


Une entit dtache peut tre modifie Pour que ces modifications soient enregistres dans la BD, il est ncessaire de rattacher lentit un GE (pas ncessairement celui do elle a t dtache) par la mthode merge

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 74

merge(A)
Renvoie une entit gre A ; plusieurs cas : Si A est une entit dtache, son tat est copi dans une entit gre A qui a la mme identit que A (si A nexiste pas dj, il est cr) Si A est nouvelle une nouvelle entit gre A est cr et ltat de A est copi dans A (un id automatique ne sera mis dans A quau commit) Si A est dj gre, merge renvoie A ; en plus merge cascade pour tous les associations avec lattribut CascadeType.MERGE

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 75

merge(A)
Si A a t marque supprime par la mthode remove, une IllegalArgumentException est lance

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 76

merge(A)
Attention, la mthode merge nattache pas A Elle retourne une entit gre qui a la mme identit dans la BD que lentit passe en paramtre, mais a nest pas le mme objet ( sauf si A tait dj gre) Aprs un merge, lapplication devra donc, sauf cas exceptionnel, ne plus utiliser lobjet A ; on pourra avoir ce type de code :

a = em.merge(a);
lobjet anciennement point par a ne sera plus rfrenc

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 77

En dehors dune transaction (1)


Les mthodes suivantes (read only) peuvent tre lances en dehors dune transaction : find, getReference, refresh et requtes (query) Les mthodes persist, remove, merge peuvent tre excutes en dehors dune transaction ; les modifications quelles ont provoques seront enregistres par un flush ds quune transaction est active Les mthodes flush, lock et modifications de masse (executeUpdate) ne peuvent tre lances en dehors dune transaction
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 78

En dehors dune transaction (2)


En fait, certains SGBD se mettent en mode autocommit lorsque des modifications sont effectues sur des entits gres en dehors dune transaction, ce qui peut poser de srieux problmes (en cas de rollback de la transaction par lapplication, ces modifications ne seront pas invalides) Il est donc conseill de neffectuer les modifications sur les entits gres que dans le contexte dune transaction, ou au moins de tester le comportement du SGBD
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 79

Transaction non termine

Il ne faut jamais oublier de terminer une transaction par commit() ou rollback() car le rsultat dpend du fournisseur de persistance et du SGBD

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 80

IV. Identit des entits

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 81

Cl primaire
Une entit doit avoir un attribut qui correspond la cl primaire dans la table associe La valeur de cet attribut ne doit jamais tre modifie par lapplication ds que lentit correspond une ligne de la base Cet attribut doit tre dfini dans lentit racine dune hirarchie dhritage (uniquement cet endroit dans toute la hirarchie dhritage) Une entit peut avoir une cl primaire composite (pas recommand)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 82

Annotation
Lattribut cl primaire est dsign par lannotation @Id Pour une cl composite on utilise @EmbeddedId ou @IdClass

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 83

Type de la cl primaire
Le type de la cl primaire (ou des champs dune cl primaire compose) doit tre un des types suivants: o type primitif Java o classe qui enveloppe un type primitif (Wrapper) comme Integer o java.lang.String o java.util.Date o java.sql.Date Ne pas utiliser les types numriques non entiers
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 84

Gnration automatique de cl
Si la cl est de type numrique entier, lannotation @GeneratedValue indique que la cl primaire sera gnre automatiquement par le SGBD Cette annotation peut avoir un attribut strategy qui indique comment la cl sera gnre (il prend ses valeurs dans lnumration GeneratorType)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 85

Types de gnration
AUTO : le type de gnration est choisi par le fournisseur de persistance, selon le SGBD (squence, table,) ; valeur par dfaut SEQUENCE : une squence est utilise IDENTITY : une colonne de type IDENTITY est utilise TABLE : une table qui contient la prochaine valeur de lidentificateur est utilise On peut aussi prciser le nom de la squence ou de la table avec lattribut generator
Adel ELJ (Architecte J2EE)

Esprit 2009/2010

Page 86

Gnrateurs didentificateurs
Les annotations @SequenceGenerator et @TableGenerator peuvent annoter l'identificateur de l'entit ou l'entit elle-mme qui les utilise, ou mme une autre entit Si le gnrateur ne sert que dans une seule classe, il vaut mieux mettre lannotation avec lannotation @Id de la classe Sinon, une entre dans un des fichiers XML de configuration de JPA, plutt quune annotation, peut tre un bon emplacement
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 87

Exemple de gnrateur

@SequenceGenerator( @SequenceGenerator( name == "emp_seq", name "emp_seq", sequenceName == "emp_seq", sequenceName "emp_seq", allocationSize == 10, allocationSize 10, initialValue == 600) initialValue 600)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 88

Exemple d'utilisation du gnrateur

@Id @Id @GeneratedValue( @GeneratedValue( strategy == GenerationType.SEQUENCE, strategy GenerationType.SEQUENCE, generator == "emp_seq") generator "emp_seq") public long getId() [[ public long getId() return id; return id; }}

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Valeur d'incrment d'une squence ( revoir)

Page 89

Si une squence utilise par JPA est cre en dehors de JPA, il faut que la valeur de prallocation de JPA (gale 50! par dfaut) corresponde la valeur dincrmentation de la squence ; on aura alors souvent ce type dannotation : @SequenceGenerator( @SequenceGenerator( name="seq3", name="seq3", sequenceName="seq3", sequenceName="seq3", initialValue="125, initialValue="125, allocationSize="20") allocationSize="20")
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 90

persist et id automatique
La spcification nimpose rien sur le moment o la valeur de lidentificateur est mise dans lobjet gr La seule assurance est quaprs un flush dans la base de donnes (donc un commit) lidentificateur aura dj reu sa valeur Avec TopLink et Oracle (et peut-tre avec dautres produits), la valeur de lidentificateur est mise ds lappel de persist, sans attendre le commit, mais il est risqu pour la portabilit de lutiliser
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 91

Cl composite
Pas recommand, mais une cl primaire peut tre compose de plusieurs colonnes Peut arriver quand la BD existe dj ou quand la classe correspond une table association (association M:N) 2 possibilits : o @IdClass o @EmbeddedId et @Embeddable

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 92

Classe pour la cl composite


Dans les 2 cas, la cl primaire doit tre reprsente par une classe Java dont les attributs correspondent aux composants de la cl primaire La classe doit tre public, possder un constructeur sans paramtre, tre srialisable et redfinir equals et hashcode

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 93

Premire mthode: @IdClass


@IdClass correspond au cas o la classe entit comprend plusieurs attributs annots par @Id La classe entit est annote par @IdClass qui prend en paramtre le nom de la classe cl primaire La classe cl primaire nest pas annote (comme @Embeddable) ; ses attributs ont les mmes noms et mmes types que les attributs annots @Id dans la classe entit
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 94

Exemple avec @IdClass


@Entity @Entity @IdClass(EmployePK.class) @IdClass(EmployePK.class) public class Employe { public class Employe { @Id @Id private String nom; private String nom; @Id @Id Date dateNaissance; Date dateNaissance; ... ... } } // Classe PK sans annotations // Classe PK sans annotations public class EmployePK { public class EmployePK { private String nom; private String nom; private Date dateNaissance; private Date dateNaissance; ... ... } }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 95

Recherche par cls composite


1. Mthode find: Il faut crer une instance de la classe PK et la passer comme deuxime argument la mthode find.

public Employee findEmployee(String nom, Date d) { public Employee findEmployee(String nom, Date d) { return em.find(Employee.class, return em.find(Employee.class, new EmployeeId(nom, d)); new EmployeeId(nom, d)); }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 96

Recherche par cls composite


2. JPQL: utiliser directement les champs dfinis dans lEntity Employee.
public Employee findEmployee(String nom, Date d) { public Employee findEmployee(String nom, Date d) { Query q = em.createQuery("SELECT e " + Query q = em.createQuery("SELECT e " + "FROM Employee e " + "FROM Employee e " + "WHERE e.nom = ?1 AND e.dateNaissance = ?2"); "WHERE e.nom = ?1 AND e.dateNaissance = ?2"); return (Employee)q.setParameter(1, nom) return (Employee)q.setParameter(1, nom) .setParameter(2, d) .setParameter(2, d) .getSingleResult(); .getSingleResult(); } }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 97

Deuxime mthode: @EmbeddedId


@EmbeddedId correspond au cas o la classe entit comprend un seul attribut annot @EmbeddedId La classe cl primaire est annot par @Embeddable Attention: Le type daccs (par champs ou proprits) de la classe embeddable doit tre le mme que celui de lentit dont la cl primaire est dfinie
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 98

Exemple avec @EmbeddedId


@Entity @Entity public class Employe { public class Employe { @EmbeddedId @EmbeddedId private EmployePK id; private EmployePK id; ... ... } } @Embeddable @Embeddable public class EmployePK { public class EmployePK { private String nom; private String nom; private Date dateNaissance; private Date dateNaissance; ... ... } }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 99

Recherche par cls composite


1. Mthode find: Il faut crer une instance de la classe PK et la passer comme deuxime argument la mthode find.

public Employee findEmployee(String nom, Date d) { public Employee findEmployee(String nom, Date d) { return em.find(Employee.class, return em.find(Employee.class, new EmployeeId(nom, d)); new EmployeeId(nom, d)); }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 100

Recherche par cls composite


2. EJBQL: different % la mthode IdClass : Il faut traverser la classe PK.
public Employee findEmployee(String nom, Date d) { public Employee findEmployee(String nom, Date d) { Query q = em.createQuery("SELECT e " + Query q = em.createQuery("SELECT e " + "FROM Employee e " + "FROM Employee e " + "WHERE e.id.nom = ?1 AND e.id.dateNaissance = ?2"); "WHERE e.id.nom = ?1 AND e.id.dateNaissance = ?2"); Return (Emplyee)q.setParameter(1, nom) Return (Emplyee)q.setParameter(1, nom) .setParameter(2, d) .setParameter(2, d) .getSingleResult(); .getSingleResult(); } }
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 101

V. Associations

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 102

Gnralits
Une association peut tre uni ou bidirectionnelle Elle peut tre de type 1:1, 1:N, N:1 ou M:N Les associations doivent tre indiques par une annotation sur la proprit correspondante, pour que JPA puisse les grer correctement Exemple: @ManyToOne @ManyToOne public Departement getDepartement() { public Departement getDepartement() { ... ... } }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Reprsentation des associations 1:N et M:N


Reprsentation des associations 1:N et M:N

Page 103

Elles sont reprsentes par des collections ou maps qui doivent tre dclares par un des types interface suivants (de java.util) : o Collection o Set o List o Map Les variantes gnriques sont conseilles ; par exemple Collection<Employe>
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 104

Types utiliser
Le plus souvent Collection sera utilis Set peut tre utile pour liminer les doublons Les types concrets, tels que HashSet ou ArrayList, ne peuvent tre utiliss que pour des entits nouvelles ; ds que lentit est gre, les types interfaces doivent tre utiliss (ce qui permet au fournisseur de persistance dutiliser son propre type concret) List peut tre utilis pour conserver un ordre mais ncessite quelques prcautions

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 105

Ordre dans les collections


Lordre dune liste n'est pas ncessairement prserv dans la base de donnes De plus, lordre en mmoire doit tre maintenu par le code (pas automatique) Tout ce quon peut esprer est de rcuprer les entits associes dans la liste avec un certain ordre lors de la rcupration dans la base, en utilisant lannotation @OrderBy

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 106

@OrderBy
Cette annotation indique dans quel ordre sont rcupres les entits associes Il faut prciser un ou plusieurs attributs qui dterminent l'ordre Chaque attribut peut tre prcis par ASC ou DESC (ordre ascendant ou descendant); ASC par dfaut Les diffrents attributs sont spars par une virgule Si aucun attribut n'est prcis, l'ordre sera celui de la cl primaire
Adel ELJ (Architecte J2EE)

Esprit 2009/2010

Page 107

Exemples
@Entity @Entity public class Departement {{ public class Departement ... ... @OneToMany(mappedBy="departement") @OneToMany(mappedBy="departement") @OrderBy("nomEmploye") @OrderBy("nomEmploye") public List<Employe> getEmployes() {{ public List<Employe> getEmployes() ... ... @OrderBy("poste DESC, nomEmploye ASC") @OrderBy("poste DESC, nomEmploye ASC")

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 108

Associations bidirectionnelles
Le dveloppeur est responsable de la gestion correcte des 2 bouts de lassociation Par exemple, si un employ change de dpartement, les collections des employs des dpartements concerns doivent tre modifies Un des 2 bouts est dit propritaire de lassociation

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 109

Bout propritaire
Pour les associations autres que M:N ce bout correspond la table qui contient la cl trangre qui traduit lassociation Pour les associations M:N le dveloppeur peut choisir arbitrairement le bout propritaire Lautre bout (non propritaire) est qualifi par lattribut mappedBy qui donne le nom de lattribut dans le bout propritaire qui correspond la mme association
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 110

Exemple
Dans la classe Employe : Dans la classe Employe :

@ManyToOne @ManyToOne public Departement getDepartement() { public Departement getDepartement() { return departement; return departement; } }
Dans la classe Departement : Dans la classe Departement :

@OneToMany(mappedBy="departement") @OneToMany(mappedBy="departement") public Collection<Employe> getEmployes() { public Collection<Employe> getEmployes() { return employes; return employes; } }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Meilleure pratique: gestion de lassociation

Page 111

Pour faciliter la gestion des 2 bouts d'une association le code peut comporter une mthode qui effectue tout le travail En particulier, dans les associations 1-N, le bout 1 peut comporter ce genre de mthode (dans la classe Departement dune association dpartement-employ) : public void ajouterEmploye(Employe e) { public void ajouterEmploye(Employe e) { this.employes.add(e); this.employes.add(e); e.setDept(this); e.setDept(this); } }
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 112

Annotation @JoinColumn
Cette annotation donne le nom de la colonne cl trangre qui reprsente l'association dans le modle relationnel Elle doit tre mise du ct propritaire (qui contient la cl trangre) Sans cette annotation, le nom est dfini par dfaut de la manire suivante: <entit_but>_<cl_primaire_entit_but>
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 113

Exemple
Pour l'association qui dtermine le dpartement d'un employ Entit but Cl primaire Entit but o Par dfaut, la colonne cl trangre place dans la table EMPLOYE s'appellera Departement_ID Pour changer ce nom (dans la classe Employe) voici un exemple:

@ManyToOne @ManyToOne @JoinColumn(name="DEPT_ID") @JoinColumn(name="DEPT_ID") public Departement getDepartement() { public Departement getDepartement() {
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 114

Annotation @JoinColumns
Lannotation @JoinColumns permet dindiquer le nom des colonnes qui constituent la cl trangre dans le cas o il y en a plusieurs (si la cl primaire rfrence contient plusieurs colonnes) En ce cas, les annotations @JoinColumn doivent ncessairement comporter un attribut referencedColumnName pour indiquer quelle colonne est rfrence (parmi les colonnes de la cl primaire rfrence)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 115

Exemple

@JoinColumns({ @JoinColumns({ @JoinColumn(name="n1", @JoinColumn(name="n1", referencedColumnName="c1"), referencedColumnName="c1"), @JoinColumn(name="n2", @JoinColumn(name="n2", referencedColumnName="c2") referencedColumnName="c2") }) })

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 116

Persistance automatique
Afin de faciliter le maintien de cette cohrence, il est possible dindiquer JPA que les objets associs un objet persistant doivent tre automatiquement rendus persistants Pour cela il suffit dajouter un attribut cascade dans les informations de mapping de lassociation

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 117

Attribut cascade
Les annotations qui dcrivent les associations entre objets peuvent avoir un attribut cascade pour indiquer que certaines oprations du GE doivent tre appliques aux objets associs Ces oprations sont PERSIST, REMOVE, REFRESH et MERGE ; ALL correspond toutes ces oprations Par dfaut, aucune opration nest applique transitivement
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 118

Exemples

@OneToMany( @OneToMany( cascade=CascadeType.PERSIST) cascade=CascadeType.PERSIST) @OneToMany( @OneToMany( cascade={CascadeType.PERSIST, cascade={CascadeType.PERSIST, CascadeType.MERGE}) CascadeType.MERGE})

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 119

Direction des relations (directionality)

Unidirectionnelle
On ne peut aller que du bean A vers le bean B

Bidirectionnelle
On peut aller du bean A vers le bean B et inversement

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 120

Association 1:1
Annotation @OneToOne Reprsente par une cl trangre ajoute dans la table qui correspond au ct propritaire Exemple : @OneToOne @OneToOne public Adresse getAdresse() { public Adresse getAdresse() { } }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 121

Association 1:1 Unidirectionnelle

Order

Shipment

Navigabilit Navigabilit unidirectionnelle unidirectionnelle

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 122

Association 1:1 Unidirectionnelle, le bean Order


@Entity(name="OrderUni") @Entity(name="OrderUni") public class Order implements Serializable { public class Order implements Serializable {
private int id; private int id; private String orderName; private String orderName;

private Shipment shipment; private Shipment shipment;


public Order() { public Order() { id = (int)System.nanoTime(); id = (int)System.nanoTime(); } } @Id @Id public int getId() { public int getId() { return id; return id; } } public Shipment getShipment() { public Shipment getShipment() { return shipment; return shipment; } }
Esprit 2009/2010

@OneToOne(cascade={CascadeType.PERSIST}) @OneToOne(cascade={CascadeType.PERSIST})

Adel ELJ (Architecte J2EE)

Page 123

Association 1:1 Unidirectionnelle, le bean Shipment


@Entity(name="ShipmentUni") @Entity(name="ShipmentUni") public class Shipment implements Serializable { public class Shipment implements Serializable {
private int id; private int id; private String city; private String city; private String zipcode; private String zipcode;

public Shipment() { public Shipment() { id = (int)System.nanoTime(); id = (int)System.nanoTime(); } } @Id @Id public int getId() { public int getId() { return id; return id; } } public void setId(int id) { public void setId(int id) { this.id = id; this.id = id; } }
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 124

Association 1:1, rsultat mapping

Nom par Nom par dfaut dfaut (Automatique) (Automatique)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 125

Association 1:1 Unidirectionnelle, code test


public static void editOrders(EntityManagerFactory factory) { public static void editOrders(EntityManagerFactory factory) { EntityManager manager = factory.createEntityManager(); EntityManager manager = factory.createEntityManager(); Query q = manager.createQuery("SELECT o FROM OrderUni o"); Query q = manager.createQuery("SELECT o FROM OrderUni o"); //Collection l = q.getResultList(); //Collection l = q.getResultList(); for (Object o : q.getResultList()) { for (Object o : q.getResultList()) { Order order = (Order)o; Order order = (Order)o; System.out.println("Order "+order.getId()+": System.out.println("Order "+order.getId()+": "+order.getOrderName()); "+order.getOrderName()); System.out.println("\tShipment details: System.out.println("\tShipment details: +" "+order.getShipment().getCity() "+order.getShipment().getCity()+" "+order.getShipment().getZipcode()); "+order.getShipment().getZipcode()); }
Adel ELJ (Architecte J2EE)

} } }

Esprit 2009/2010

Page 126

Association 1:1 Bidirectionnelle

Order

Shipment

Navigabilit Navigabilit bidirectionnelle bidirectionnelle

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Version bidirectionnelle: (on modifie Shipment)


@Entity(name="ShipmentBid") @Entity(name="ShipmentBid") public class Shipment implements Serializable { public class Shipment implements Serializable { private int id; private int id; private String city; private String city; private String zipcode; private String zipcode; Private Order order; Private Order order; public Shipment() { public Shipment() { id = (int)System.nanoTime(); id = (int)System.nanoTime(); } } @OneToOne(mappedBy="shipment") @OneToOne(mappedBy="shipment") public Order getOrder() { public Order getOrder() { return order; return order; } } }

Page 127

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 128

Association 1:1 Bidirectionnelle, code test


public static void editShipments(EntityManagerFactory factory) public static void editShipments(EntityManagerFactory factory) { { EntityManager manager = factory.createEntityManager(); EntityManager manager = factory.createEntityManager(); Query q = manager.createQuery("SELECT s FROM ShipmentBid s"); Query q = manager.createQuery("SELECT s FROM ShipmentBid s"); for (Object o : q.getResultList()) { for (Object o : q.getResultList()) { Shipment shipment = (Shipment)o; Shipment shipment = (Shipment)o; System.out.println("Shipment: "+shipment.getCity()+" System.out.println("Shipment: "+shipment.getCity()+" "+shipment.getZipcode()); "+shipment.getZipcode()); System.out.println("\tOrder details: System.out.println("\tOrder details: "+shipment.getOrder().getOrderName()); "+shipment.getOrder().getOrderName()); } } } }
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 129

Associations 1:N et N:1


Annotations @OneToMany et @ManyToOne Reprsente par une cl trangre dans la table qui correspond au ct propritaire (obligatoirement le ct Many )
class Employe { class Employe { class Departement { ... class Departement { ... ... @ManyToOne ... @ManyToOne @OneToMany(mappedBy="departement") public Departement getDepartement()@OneToMany(mappedBy="departement") public Departement getDepartement() public List<Employe> getEmployes() { { public List<Employe> getEmployes() { { ... ... ... ... } } } } } } } }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 130

Association 1:N
1 Commande * Ligne de commande

1 Client

* Commande

1 Scit

* Employ

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 131

Association 1:N Unidirectionnelle


Le GE gnre automatiquement une table de jointure

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 132

Associaltion 1:N exemple

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 133

Associaltion 1:N exemple

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 134

Exemple de code qui insre des compagnies

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 135

Exemple de code qui insre des compagnies

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 136

Exemple de client

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 137

1:N unidirectionnelle
public class Dept {{ public class Dept ... ... @OneToMany @OneToMany @JoinTable(name="DEPT_EMP", @JoinTable(name="DEPT_EMP", joinColumns= joinColumns= @JoinColumn(name="DEPT_ID"), @JoinColumn(name="DEPT_ID"), inverseJoinColumns= inverseJoinColumns= @JoinColumn(name="EMP_ID")) @JoinColumn(name="EMP_ID")) private Collection<Employe> employes; private Collection<Employe> employes; ... ... }}
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 138

Association 1:N Bidirectionnelle


Le GE ne gnrre pas une table de jointure. Il gnre une cl trangre dans la table ct *

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 139

Version bidirectionnelle

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 140

Version bidirectionnelle

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 141

Version bidirectionnelle

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 142

Association M:N
Annotation @ManyToMany Reprsente par une table dassociation

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 143

Association M:N (1)


Les valeurs par dfaut :
o le nom de la table association est la

concatnation des 2 tables, spares par _

o les noms des colonnes cls trangres sont les

concatnations de la table rfrence, de _ et de la colonne Id de la table rfrence

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 144

Association M:N (2)


Le ct propritaire est arbitraire Si les valeurs par dfaut ne conviennent pas, le ct propritaire doit comporter une annotation @JoinTable Lautre ct doit toujours comporter lattribut mappedBy

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 145

@JoinTable
Donne des informations sur la table association qui va reprsenter lassociation Attribut name donne le nom de la table Attribut joinColumns donne les noms des colonnes de la table qui rfrencent les cls primaires du ct propritaire de lassociation Attribut inverseJoinColumns donne les noms des colonnes de la table qui rfrencent les cls primaires du ct qui nest pas propritaire de lassociation

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 146

Exemple1(cls simples)
Ct Ct prop. prop.

Ct Ct inv. inv.

@ManyToMany @ManyToMany @JoinTable( @JoinTable( name="EMP_PROJ" name="EMP_PROJ" joinColumns = @JoinColumn(name="EMP_ID") joinColumns = @JoinColumn(name="EMP_ID") inverseJoinColumns = @JoinColumn(name="PROJ_ID") inverseJoinColumns = @JoinColumn(name="PROJ_ID") ) ) public Collection<Projet> getProjects() { public Collection<Projet> getProjects() {

Classe Employee (ct prop.)

@ManyToMany(mappedBy="projets") @ManyToMany(mappedBy="projets") public Collection<Employee> getEmployees() { public Collection<Employee> getEmployees() { Esprit 2009/2010

Classe Project (ct inv.)


Adel ELJ (Architecte J2EE)

Page 147

Exemple2 (cls composite)


Ct Ct inv. inv.

Ct Ct prop. prop.

@Id private String country; @Id private String country; @Id @Id @Column(name="EMP_ID") @Column(name="EMP_ID") private int id; private int id; @ManyToMany @ManyToMany @JoinTable( name="EMP_PROJECT", @JoinTable( name="EMP_PROJECT", joinColumns={ joinColumns={ @JoinColumn(name="EMP_COUNTRY", referencedColumnName="COUNTRY"), @JoinColumn(name="EMP_COUNTRY", referencedColumnName="COUNTRY"), @JoinColumn(name="EMP_ID", referencedColumnName="EMP_ID")}, @JoinColumn(name="EMP_ID", referencedColumnName="EMP_ID")}, inverseJoinColumns= inverseJoinColumns= @JoinColumn(name="PROJECT_ID")) @JoinColumn(name="PROJECT_ID")) private Collection<Project> projects private Collection<Project> projects

Classe Employee

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

(ct prop.)

Association M:N avec information porte par l'association

Page 148

Une association M:N peut porter une information Exemple : Association entre les employs et les projets Un employ a une (et une seule) fonction dans chaque projet auquel il participe En ce cas, il n'est pas possible de traduire l'association en ajoutant 2 collections (ou maps) comme il vient d'tre dcrit

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Classe association pour une association M:N


L'association sera traduite par une classe association

Page 149

2 possibilits pour cette classe, suivant qu'elle contient ou non un attribut identificateur (@Id) unique Le plus simple est de n'avoir qu'un seul attribut identificateur

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 150

Exemple - 1 identificateur
Association entre les employs et les projets Cas d'un identificateur unique : la classe association contient les attributs id (int), employe ( Employe), projet ( Projet) et fonction (String) L'attribut id est annot par @Id Les attributs employe et projet sont annots par @ManyToOne

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 151

Exemple - 1 identificateur
Exemple - 1 identificateur Si le schma relationnel est gnr daprs les informations de mapping par les outils associs au fournisseur de persistance, on peut ajouter une contrainte d'unicit sur (EMPLOYE_ID, PROJET_ID) qui traduit le fait qu'un employ ne peut avoir 2 fonctions dans un mme projet : @Entity @Entity @Table(uniqueConstraints= @Table(uniqueConstraints= @UniqueConstraint(columnNames = @UniqueConstraint(columnNames = {"EMPLOYE_ID","PROJET_ID"}) {"EMPLOYE_ID","PROJET_ID"}) public class Participation { public class Participation {

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 152

Exemple - 2 identificateurs (1)


Si la base de donnes existe dj, il sera frquent de devoir s'adapter une table association qui contient les colonnes suivantes (pas de colonne id): o employe_id, cl trangre vers EMPLOYE o projet_id, cl trangre vers PROJET o fonction et qui a (employe_id, projet_id) comme cl primaire

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 153

Exemple - 2 identificateurs (2)


Dans ce cas, la solution est plus complexe, et pas toujours portable dans l'tat actuel de la spcification JPA La solution donne dans les transparents suivants convient pour TopLink et Hibernate, les 2 fournisseurs de persistance les plus utiliss ; elle na pas t teste sur dautres fournisseurs

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 154

Exemple - 2 identificateurs
La difficult vient de l'criture de la classe Participation L'ide est de dissocier la fonction d'identificateur des attributs employeId et projetId de leur rle dans les associations avec les classes Projet et Employe

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 155

Exemple - 2 identificateurs
Pour viter les conflits au moment du flush, les colonnes qui correspondent aux identificateurs sont marqus non modifiables ni insrables (pas de persistance dans la BD) En effet, leur valeur sera mise par le mapping des associations 1-N vers Employe et Projet qui sera traduite par 2 cls trangres

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 156

Classes Employe et Projet


@Entity public class Employe { @Entity public class Employe { @Id public int getId() { ... } @Id public int getId() { ... } @OneToMany(mappedBy="employe") @OneToMany(mappedBy="employe") public Collection<Participation> public Collection<Participation> getParticipations() { ... } getParticipations() { ... } . . . . . . } }
@Entity public class Projet { @Entity public class Projet { @Id public int getId() { ... } @Id public int getId() { ... } @OneToMany(mappedBy="projet") @OneToMany(mappedBy="projet") public Collection<Participation> getParticipations() { public ... Collection<Participation> getParticipations() { ... } } . . . . . . } } Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Classe Participation (2 choix pour Id)

Page 157

On peut utiliser une classe Embeddable ou une IdClass pour reprsenter la cl composite de Participation Le code suivant utilise une IdClass

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 158

Classe Participation (Id)


@Entity @Entity @IdClass(ParticipationId.class) @IdClass(ParticipationId.class) public class Participation { public class Participation { // Les identificateurs "read-only" // Les identificateurs "read-only" @Id @Id @Column(name="EMPLOYE_ID", @Column(name="EMPLOYE_ID", insertable="false", updatable="false") insertable="false", updatable="false") public int getEmployeId() { } public int getEmployeId() { } @Id @Id @Column(name="PROJET_ID", @Column(name="PROJET_ID", insertable="false", updatable="false") insertable="false", updatable="false") public int getProjetId() { } public int getProjetId() { }
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 159

Classe Participation (champs)


private Employe employe; private Employe employe; private long employeId; private long employeId; private Projet projet; private Projet projet; private long projetId; private long projetId; private String fonction; private String fonction; public Participation() {{ }} public Participation()

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 160

tablir une association


Il faut viter la possibilit quun bout seulement de lassociation soit tablie et pour cela, il faut quune seule classe sen charge Pour cela, on peut faire grer lassociation entire par Projet, par Employe ou par Participation Le transparent suivant montre comment la faire grer par le constructeur de Participation

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 161

Participation (constructeurs)
public Participation() { } // Pour JPA public Participation() { } // Pour JPA public Participation(Employee employe, public Participation(Employee employe, Projet projet, Projet projet, String fonction) { String fonction) { this.employeId = employe.getId(); this.employeId = employe.getId(); this.projetId = projet.getId(); this.projetId = projet.getId(); // gestion de lassociation avec Employee // gestion de lassociation avec Employee this.employe = employe; this.employe = employe; employe.getParticipations.add(this); employe.getParticipations.add(this); // gestion de lassociation avec Project // gestion de lassociation avec Project this.projet = projet; this.projet = projet; projet.getParticipations.add(this); projet.getParticipations.add(this); } this.fonction = fonction; this.fonction = fonction; }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 162

Participation (associations)
// Les associations // Les associations @ManyToOne @ManyToOne public Employe getEmploye() { public Employe getEmploye() { return employe; return employe; } } @ManyToOne @ManyToOne public Projet getProjet() { public Projet getProjet() { return projet; return projet; } } . . . . . . } }

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 163

Classe ParticipationId
public class ParticipationId implements public class ParticipationId implements Serializable { Serializable { private int employeId; private int employeId; private int projetId; private int projetId; public int getEmployeId() { ... } public int getEmployeId() { ... } public void setEmployeId(int employeId) public void setEmployeId(int employeId) { ... } { ... } public int getProjetId() { ... } public int getProjetId() { ... } public void setProjetId(int projetId) public void setProjetId(int projetId) { ... } { ... } // Redfinir aussi equals et hasCode // Redfinir aussi equals et hasCode

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 164

Rcupration des entits associes


Lorsquune entit est rcupre depuis la base de donnes par une requte (Query) ou par un find, est-ce que les entits associes doivent tre elles aussi rcupres ? Si elles sont rcupres, est-ce que les entits associes ces entits doivent elles aussi tre rcupres ? On voit que le risque est de rcuprer un trs grand nombre dentits qui ne seront pas utiles pour le traitement en cours
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 165

EAGER ou LAZY
JPA laisse le choix de rcuprer ou non immdiatement les entits associes, suivant les circonstances Il suffit de choisir le mode de rcupration de lassociation (LAZY ou EAGER) Une requte sera la mme, quel que soit le mode de rcupration Dans le mode LAZY les donnes associes ne sont rcupres que lorsque cest vraiment ncessaire
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 166

Rcupration retarde (LAZY)


Dans le cas o une entit associe nest pas rcupre immdiatement, JPA remplace lentit par un proxy , objet qui permettra de rcuprer lentit plus tard si besoin est Ce proxy contient la cl primaire qui correspond lentit non immdiatement rcupre Il est possible de lancer une requte avec une rcupration immdiate, mme si une association est en mode LAZY (join fetch tudi plus loin)
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Page 167

Comportement par dfaut de JPA


Par dfaut, JPA ne rcupre immdiatement que les entits associes par des associations dont le but est One (une seule entit lautre bout) : OneToOne et ManyToOne (mode EAGER) Pour les associations dont le but est Many (une collection lautre bout), OneToMany et ManyToMany, par dfaut, les entits associes ne sont pas rcupres immdiatement (mode LAZY)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Indiquer le type de rcupration des entits associes

Page 168

Lattribut fetch dune association permet dindiquer une rcupration immdiate des entits associes (FetchType.EAGER) ou une rcupration retarde ( FetchType.LAZY) si le comportement par dfaut ne convient pas Exemple : @OneToMany(mappedBy="departement", @OneToMany(mappedBy="departement", fetch=FetchType.EAGER) fetch=FetchType.EAGER) public Collection<Employe> getEmployes() public Collection<Employe> getEmployes()

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Mode de rcupration des attributs


Page 169

Les attributs aussi peuvent tre rcuprs en mode retard Le mode de rcupration par dfaut est le mode EAGER pour les attributs (ils sont chargs en mme temps que lentit) Si un attribut est dun type de grande dimension (LOB), il peut aussi tre marqu par @Basic(fetch=FetchType.LAZY) ( utiliser avec parcimonie) Cette annotation nest quune suggestion au GE, quil peut ne pas suivre

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 170

VI. Hritage

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 171

Stratgies
A ce jour, les implmentations de JPA doivent obligatoirement offrir 3 stratgies pour la traduction de lhritage :
o une seule table pour une hirarchie dhritage

(SINGLE_TABLE) o une table par classe ; les tables sont jointes pour reconstituer les donnes (JOINED) o une table distincte par classe concrte (TABLE_PER_CLASS)

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 172

Une table par hirarchie


Sans doute la stratgie la plus utilise Valeur par dfaut de la stratgie de traduction de lhritage Elle est performante et permet le polymorphisme Mais elle induit beaucoup de valeurs NULL dans les colonnes si la hirarchie est complexe

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 173

Une table par hirarchie


@Entity @Entity @Table(name="Animal") @Table(name="Animal") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="TYPE") @DiscriminatorColumn(name="TYPE") public class Animal { public class Animal { @Id private int id; @Id private int id; @Column(name="AVG_WEIGHT") @Column(name="AVG_WEIGHT") private int averageWeight; private int averageWeight; ... ... } } @Entity @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @Inheritance(strategy=InheritanceType.SINGLE_TABLE) public class Dog extends Animal{ public class Dog extends Animal{ @Column(name="BREED") @Column(name="BREED") private String breed; private String breed; ... ... } }
Esprit 2009/2010
Adel ELJ (Architecte J2EE)

Mode de rcupration des attributs


create table Animal create table Animal (( ID Number, ID Number, TYPE varchar(255), TYPE varchar(255), AVG_WEIGHT Number, AVG_WEIGHT Number, BREED varchar(255) BREED varchar(255) ); );

Page 174

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 175

Une table par classe drive


@Entity @Entity @Inheritance(strategy=InheritanceType.JOINED) @Inheritance(strategy=InheritanceType.JOINED) public class Animal{ public class Animal{ @Id private int id; @Id private int id; @Column(name="AVG_WEIGHT") @Column(name="AVG_WEIGHT") private int averageWeight; private int averageWeight; ... ... }} @Entity @Entity @InheritanceJoinColumn(name="DOGGY_ID") @InheritanceJoinColumn(name="DOGGY_ID") public class Dog extends Animal{ public class Dog extends Animal{ @Column(name="BREED") @Column(name="BREED") private String breed; private String breed; ... ... }}

Esprit 2009/2010

Adel ELJ (Architecte J2EE)

Page 176

Une table par classe drive


create table Animal create table Animal (( ID Number, ID Number, TYPE varchar(255), TYPE varchar(255), AVG_WEIGHT Number AVG_WEIGHT Number ); ); create table Doggy create table Doggy (( DOGGY_ID Number, DOGGY_ID Number, BREED varchar(255) BREED varchar(255) ); );

Esprit 2009/2010

Adel ELJ (Architecte J2EE)