Académique Documents
Professionnel Documents
Culture Documents
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
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
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
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
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
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
Page 9
Esprit 2009/2010
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
Page 11
Esprit 2009/2010
Page 12
public String getNom() { return nom; } public void setNom(String nom) { this.nom = nom; }
Esprit 2009/2010
Page 13
Esprit 2009/2010
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
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
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
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
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
Page 19
Esprit 2009/2010
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
Page 21
II. Entits
Esprit 2009/2010
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
Page 23
Esprit 2009/2010
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
Page 25
Esprit 2009/2010
Page 26
Page 27
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
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)
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
find query
Esprit 2009/2010
Page 30
Esprit 2009/2010
Page 31
Esprit 2009/2010
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
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
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
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
Esprit 2009/2010
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
Page 39
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
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
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
Esprit 2009/2010
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
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
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
Page 48
Page 49
Page 50
Page 51
Esprit 2009/2010
Page 52
Interface EntityManager
Elle reprsente un GE Limplmentation de linterface fournie par le fournisseur de persistance
Esprit 2009/2010
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
Page 54
Esprit 2009/2010
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
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
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
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
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
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
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
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
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
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
Page 72
Esprit 2009/2010
Page 73
Esprit 2009/2010
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
Page 75
merge(A)
Si A a t marque supprime par la mthode remove, une IllegalArgumentException est lance
Esprit 2009/2010
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
Page 77
Page 78
Page 79
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
Page 80
Esprit 2009/2010
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
Page 82
Annotation
Lattribut cl primaire est dsign par lannotation @Id Pour une cl composite on utilise @EmbeddedId ou @IdClass
Esprit 2009/2010
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
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
Page 88
@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
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
Page 92
Esprit 2009/2010
Page 93
Page 94
Esprit 2009/2010
Page 95
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
Page 96
Esprit 2009/2010
Page 97
Page 98
Esprit 2009/2010
Page 99
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
Page 100
Page 101
V. Associations
Esprit 2009/2010
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
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
Page 105
Esprit 2009/2010
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
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
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
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
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
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
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
Page 119
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
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
Page 121
Order
Shipment
Esprit 2009/2010
Page 122
@OneToOne(cascade={CascadeType.PERSIST}) @OneToOne(cascade={CascadeType.PERSIST})
Page 123
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
Esprit 2009/2010
Page 125
} } }
Esprit 2009/2010
Page 126
Order
Shipment
Esprit 2009/2010
Page 127
Esprit 2009/2010
Page 128
Page 129
Esprit 2009/2010
Page 130
Association 1:N
1 Commande * Ligne de commande
1 Client
* Commande
1 Scit
* Employ
Esprit 2009/2010
Page 131
Esprit 2009/2010
Page 132
Esprit 2009/2010
Page 133
Esprit 2009/2010
Page 134
Esprit 2009/2010
Page 135
Esprit 2009/2010
Page 136
Exemple de client
Esprit 2009/2010
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
Esprit 2009/2010
Page 139
Version bidirectionnelle
Esprit 2009/2010
Page 140
Version bidirectionnelle
Esprit 2009/2010
Page 141
Version bidirectionnelle
Esprit 2009/2010
Page 142
Association M:N
Annotation @ManyToMany Reprsente par une table dassociation
Esprit 2009/2010
Page 143
Esprit 2009/2010
Page 144
Esprit 2009/2010
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
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() {
@ManyToMany(mappedBy="projets") @ManyToMany(mappedBy="projets") public Collection<Employee> getEmployees() { public Collection<Employee> getEmployees() { Esprit 2009/2010
Page 147
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
(ct prop.)
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
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
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
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
Page 152
Esprit 2009/2010
Page 153
Esprit 2009/2010
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
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
Page 156
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
Page 158
Page 159
Esprit 2009/2010
Page 160
Esprit 2009/2010
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
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
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
Page 164
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
Page 167
Esprit 2009/2010
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
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
Page 170
VI. Hritage
Esprit 2009/2010
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
Page 172
Esprit 2009/2010
Page 173
Page 174
Esprit 2009/2010
Page 175
Esprit 2009/2010
Page 176
Esprit 2009/2010