Académique Documents
Professionnel Documents
Culture Documents
JPA 2.0
Prsentation de JPA Entits persistantes Gestionnaire dentits Identit des entits Associations entre entits Complments sur les associations (persistance et rcupration des entits associes, ordre des listes, orphelins) Hritage entre entits
R. Grin JPA page 2
EJB
Java EE (Enterprise Edition) est une plateforme de dveloppement et un ensemble de spcifications pour le dveloppement dapplications dentreprises multi-tiers EJB (Enterprise JavaBeans) fait partie de Java EE Dfinit un cadre (framework) pour lutilisation de composants mtier rutilisables par des serveurs dapplications Java
Prsentation de JPA
R. Grin
JPA
page 3
R. Grin
JPA
page 4
JPA
JPA (Java persistence API) est la partie de la spcification EJB qui concerne la persistance des composants dans une base de donnes relationnelle JPA peut tre utilis par toutes les applications Java, mme en dehors de Java EE Cest lAPI ORM (Object-Relational Mapping) standard pour la persistance des objets Java JPA 2.0 fait partie de EJB 3.1, inclus dans Java EE 6
R. Grin JPA page 5
Spcification JPA
Pour plus de prcisions, lire la spcification ladresse http://jcp.org/aboutJava/communityprocess/pfd/js r317/index.html
R. Grin
JPA
page 7
R. Grin
JPA
page 8
Avertissement
JPA est le plus souvent utilis dans le contexte dun serveur dapplications (Java EE) Ce cours tudie lutilisation de JPA par une application autonome, en dehors de tout serveur dapplications Quelques informations sur lutilisation de JPA avec un serveur dapplications sont donnes dans ce cours mais sans entrer dans les dtails Les diffrences sont essentiellement lies la faon dobtenir un gestionnaire dentits et aux transactions ; presque tout le reste est identique
R. Grin JPA page 9
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 EclipseLink est limplmentation de rfrence de la spcification JPA 2.0 (http://www.eclipse.org/eclipselink/) Dautres implmentations : Hibernate Entity Manager, OpenJPA, BEA Kodo
R. Grin JPA page 10
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 (importations semblables pour toutes les annotations)
R. Grin JPA page 11
@Entity
Cette annotation peut avoir un attribut name qui donne le nom de lentit (rarement utilis) Par dfaut, le nom de lentit est le nom terminal (sans le nom du paquetage) de la classe Exemple : @Entity(name="dept") public class Departement {
R. Grin
JPA
page 12
Vocabulaire
Dans la suite de ce cours et quand il ny aura pas ambigut, entit dsignera soit une classe entit, soit une instance de classe entit, suivant le contexte
R. Grin
JPA
page 13
R. Grin
JPA
page 14
R. Grin
JPA
page 16
Configuration de la connexion
Il est ncessaire dindiquer au fournisseur de persistance comment il peut se connecter la base de donnes Les informations peuvent 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 partie 2 du cours sur JPA ; section Configuration dune unit de persistance )
R. Grin JPA page 18
Exemple (1/3)
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="employes" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.Persi stenceProvider</provider> <class>jpa.Departement</class> <class>jpa.Employe</class>
Exemple (2/3)
<properties> <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/> <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@cl.truc.fr:1521:XE"/>
R. Grin
JPA
page 19
R. Grin
JPA
page 20
Exemple (3/3)
<property name="javax.persistence.jdbc.user" value="toto"/> <property name="javax.persistence.jdbc.password" value="xxxxx"/> </properties> </persistence-unit> </persistence>
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.
R. Grin
JPA
page 21
R. Grin
JPA
page 22
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
R. Grin JPA page 29
GE contexte de persistance
Dans le cadre dune application autonome, la relation est simple : un GE possde un contexte de persistance, qui nappartient qu lui et il le garde pendant toute son existence Lorsque le GE est gr par un serveur dapplications, la relation est plus complexe ; un contexte de persistance peut se propager dun GE un autre et il peut tre ferm automatiquement la fin de la transaction en cours (pas tudi dans ce cours)
R. Grin JPA page 30
Caractristiques
Seules les entits peuvent tre n passes en paramtre dune mthode dun EntityManager ou dun Query n renvoyes par une requte (Query) le but dune association rfrences dans une requte JPQL Une classe entit peut utiliser dautres classes pour conserver des tats persistants (MappedSuperclass ou Embeddable tudies plus loin ; depuis JPA 2, les 3 derniers points sont aussi vrais pour les Embeddable)
n n
page 31 R. Grin JPA page 32
Entits
R. Grin
JPA
R. Grin
JPA
page 34
2 types daccs
Ltat persistant dun objet est constitu par les valeurs de ses attributs Le fournisseur de persistance peut accder la valeur dun attribut de 2 faons n soit en accdant directement la variable dinstance ; cest laccs par champ n soit en passant par les accesseurs (getter ou setter) ; cest laccs par proprit
R. Grin
JPA
page 36
R. Grin
JPA
page 37
@Access(PROPERTY)
Si laccs par dfaut est laccs par champ et quun getter est annot avec @Access(AccessType.PROPERTY), il ne faut pas oublier dannoter le champ correspondant avec @Transient Sinon lattribut sera rendu persistant dans 2 colonnes de la base de donnes
Donner explicitement le mode daccs de la classe par une annotation (ne pas oublier !) : @Entity @Access(AccessType.FIELD) public class Annoter le getter par son mode daccs : @Access(AccessType.PROPERTY) String getNom() { Annoter par @Transient le champ correspondant la proprit : @Transient String nom;
JPA page 41
2.
3.
R. Grin
R. Grin
JPA
page 42
R. Grin
JPA
page 43
Attributs persistants
Par dfaut, tous les attributs dune entit sont persistants Lannotation @Basic indique quun attribut est persistant mais elle nest donc indispensable que si on veut prciser des informations sur cette persistance (par exemple, une rcupration retarde) Seuls les attributs dont la variable est transient, ou qui sont annots par @Transient, ne sont pas persistants
R. Grin JPA page 46
R. Grin
JPA
page 47
R. Grin
JPA
page 48
Types basic
Types primitifs (int, double,) String, BigInteger, BigDecimal, classes enveloppes de type primitifs (Integer,) Date (des paquetages util et sql), Calendar, Time, Timestamp Enumrations Tableaux de byte, Byte, char, Character Plus gnralement Serializable (un tel attribut sera sauvegard comme un tout dans la base, dans une seule colonne)
R. Grin JPA page 49
Nouvelle
persist
Gre
merge remove
Dtache
find Query BD
Supprime
R. Grin JPA page 53
R. Grin
JPA
page 56
Nom de table
Pour donner la table un autre nom que le non de la classe, il faut ajouter une annotation @Table Exemple :
@Entity @Table(name = "AUTRE_NOM") public class Classe { ... }
R. Grin
JPA
page 57
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="NOM_CLIENT", updatable=false, length=80) private String nomClient;
R. Grin JPA page 59
10
Exemple
@Embeddable public class Adresse { private int numero; private String rue; private String ville; . . . } @Entity public class Employe { @Embedded private Adresse adresse; ... Optionnel
R. Grin JPA page 61
R. Grin
JPA
page 62
R. Grin
JPA
page 63
R. Grin
JPA
page 64
@AttributeOverride(s)
Un champ annot par @Embedded peut tre complt par une annotation @AttributeOverride, ou plusieurs de ces annotations insres dans une annotation @AttributeOverrides Ces annotations permettent dindiquer le nom dune ou de plusieurs colonnes dans la table de lentit Elles peuvent aussi tre utilises si une classe insre est rfrence par plusieurs classes entits diffrentes
R. Grin JPA page 66
11
Exemple
@Entity public class Employe { @Embedded @AttributeOverrides({ @AttributeOverride( name="ville", column=@column(name="ville_travail")), @AttributeOverride(...) }) // Adresse du travail private Adresse adresseTravail;
R. Grin JPA page 67
R. Grin
JPA
page 69
( utiliser avec parcimonie car peut gnrer un accs supplmentaire la base de donnes et provoquer des problmes si lentit est dtache) Cette annotation nest quune suggestion au GE, quil peut ne pas suivre R. Grin JPA page 70
Exemple
@Enumerated(EnumType.STRING) private TypeEmploye typeEmploye;
R. Grin
JPA
page 72
12
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)
R. Grin JPA page 73
R. Grin
JPA
page 74
Exemple
@Temporal(TemporalType.DATE) private Calendar dateEmb;
Collection dlments
JPA 2 a ajout la possibilit de sauvegarder dans une table part les attributs qui sont des collections dlments de type basic ou Embeddable, appeles collection dlments dans la spcification Ces attributs doivent tre annots avec lannotation @ElementCollection Si lannotation nest pas utilise, lattribut est considr comme un Serializable et sauvegard comme un LOB dans la base
R. Grin
JPA
page 75
R. Grin
JPA
page 76
Annotation @ElementCollection
Le mode de rcupration des lments de la collection est LAZY par dfaut (voir la section sur les complments sur les associations plus loin dans ce support) Il est possible dindiquer un mode EAGER avec lannotation @ElementCollection
R. Grin
JPA
page 78
13
Exemples
@ElementCollection private Set<String> synonymes = new HashSet<String>(); @ElementCollection(fetch=FetchType.EAGER) private Set<String> synonymes = new HashSet<String>();
R. Grin
JPA
page 79
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
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 dunicit, 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 (en SQL) Pour plus de dtails voir la fin de la 2me partie de ce cours sur JPA ou la spcification JPA
R. Grin JPA page 82
R. Grin
JPA
page 81
Exemple
@Entity @Table(name="PARTICIPATION2", uniqueConstraints = @UniqueConstraint( columnNames = {"EMPLOYE_ID", "PROJET_ID"}) ) public class Participation { ... }
R. Grin JPA page 83
14
R. Grin
JPA
page 85
R. Grin
JPA
page 86
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 dentits (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
R. Grin JPA page 87 R. Grin
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
JPA
page 88
R. Grin
JPA
page 89
15
Interface EntityManager
Elle reprsente un GE Implmentation fournie par le fournisseur de persistance
R. Grin
JPA
page 93
R. Grin
JPA
page 94
Types de GE
GE gr par le container (uniquement disponible dans un serveur dapplications ; pas tudi dans ce cours) ; le contexte de persistance nexiste souvent que le temps dune seule transaction GE gr par lapplication (seul type disponible en dehors dun serveur dapplications) ; le contexte de persistance reste attach au GE pendant toute son existence
R. Grin
JPA
page 95
16
Fabrique de GE
La classe Persistence permet dobtenir une fabrique de gestionnaire dentits par la mthode createEntityManagerFactory 2 variantes surcharges de cette mthode : n 1 seul paramtre qui donne le nom de lunit de persistance (dfinie dans le fichier persistence.xml) me paramtre de type Map qui contient n Un 2 des valeurs qui vont craser les proprits par dfaut contenues dans persistence.xml
R. Grin JPA page 97
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
R. Grin JPA page 98
Interface EntityManagerFactory
Implmente par les fabriques de GE renvoyes par la mthode createEntityManagerFactory Elle contient la mthode isOpen() utilise pour savoir si une fabrique est ouverte et la mthode close() qui doit tre lance lorsque lon na plus besoin de la fabrique, pour librer les ressources quelle utilise La mthode close rend inutilisables tous les GE crs par la fabrique
R. Grin JPA page 99
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 createEntityManagerFactory ne se termine pas correctement et lance une exception
R. Grin
JPA
page 100
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)
R. Grin JPA page 101
Mthodes de EntityManager
void lock(Object entit, LockModeType lockMode) void refresh(Object entit) void clear() void detach(Object entit) boolean contains(Object entit) void joinTransaction() void close() boolean isOpen()
R. Grin JPA page 102
17
Mthodes de EntityManager
EntityTransaction getTransaction() Query createQuery(String requte) Query createNamedQuery(String nom) Query createNativeQuery(String requte) Query createNativeQuery(String requte, Class classeRsultat)
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 (mais il faudra un commit pour que ces modifications soient dfinitivement enregistres dans la BD) 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)
R. Grin JPA page 104
R. Grin
JPA
page 103
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
flush
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 elle aussi flushe Sinon, si Y est new ou removed, une exception IllegalStateException est leve et la transaction est marque pour un rollback Sinon, si Y est dtache et X possde lassociation, Y est flushe ; si Y est le bout propritaire (voir section associations plus loint), le comportement est indfini
R. Grin JPA page 106
R. Grin
JPA
page 105
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)
R. Grin JPA page 107
persist
Une entit nouvelle devient une entit gre Ltat de lentit sera sauvegard dans la BD au prochain flush ou commit Aucune autre instruction ne sera ncessaire pour que les modifications effectues ensuite sur lentit par lapplication soient enregistres au moment du commit En effet le GE conserve toutes les informations ncessaires sur les entits quil gre
R. Grin JPA page 108
18
persist(A)
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 (il aurait plutt fallu appeler la mthode merge)
R. Grin JPA page 109
EntityExistException
persist lance une exception non contrle EntityExistsException si lentit existe dj dans la base de donnes Lexception peut tre lance au moment du persist ou au moment du flush dans la base
remove
Une entit gre devient supprime Les donnes correspondantes seront supprimes de la BD
R. Grin
JPA
page 111
R. Grin
JPA
page 112
remove(A)
Si A est une entit gre, elle devient supprime (les donnes correspondantes de la base seront supprimes de la base au moment du flush du contexte de persistance) Ignor si A est nouvelle ou dj supprime Si A est dtache, une IllegalArgumentException est lance
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 sont copies dans lentit Utiliser cette mthode pour sassurer que lentit a les mmes donnes que la BD Peut tre utile pour les transactions longues
R. Grin JPA page 114
R. Grin
JPA
page 113
19
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
clear et detach
clear() vide le contexte de persistance Toutes les entits gres de ce contexte deviennent dtaches detach(entit) enlve lentit du contexte de persistance ; lentit devient dtache ; lance une IllegalArgumentException si largument nest pas une entit gre
R. Grin
JPA
page 115
R. Grin
JPA
page 116
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);
lock(A)
Le fournisseur de persistance gre les accs concurrents aux donnes de la BD reprsentes par les entits avec une stratgie optimiste lock permet de modifier la manire de grer les accs concurrents une entit A Sera tudi plus loin dans la section sur la concurrence
R. Grin
JPA
page 117
R. Grin
JPA
page 118
close
Aprs lappel de cette mthode, toutes les autres mthodes de EntityManager lancent une IllegalStateException (sauf isOpen() et getTransaction()) Il est impossible de rouvrir un EntityManager Dans un environnement gr (J2EE), la mthode est inutile puisque cest le serveur dapplications qui se charge de fermer lEntityManager
R. Grin JPA page 119
joinTransaction
Pour les applications gres par un serveur dapplications (donc hors du cadre de ce cours) lorsquun contexte de persistance est gr par lapplication et que le gestionnaire dentits a t cr alors quaucune transaction JTA ntait en cours Synchronise le contexte de persistance avec la transaction pour que le commit de la transaction provoque automatiquement le flush du contexte de persistance dans la base de donnes
R. Grin JPA page 120
20
R. Grin
JPA
page 121
R. Grin
JPA
page 122
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
R. Grin JPA page 123
merge(A)
Si A a t marque supprime par la mthode remove, une IllegalArgumentException est lance
R. Grin
JPA
page 124
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 aura souvent ce type de code : a = em.merge(a); lobjet anciennement point par a ne sera plus rfrenc
R. Grin JPA page 125
21
R. Grin
JPA
page 127
R. Grin
JPA
page 128
R. Grin
JPA
page 130
R. Grin
JPA
page 131
R. Grin
JPA
page 132
22
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)
R. Grin JPA page 133
Annotation
Lattribut cl primaire est dsign par lannotation @Id Pour une cl composite on utilise @EmbeddedId ou @IdClass
R. Grin
JPA
page 134
Type de la cl primaire
Le type de la cl primaire (ou des champs dune cl primaire compose) doit tre un des types suivants : n type primitif Java (ne pas utiliser les types numriques non entiers) n classe qui enveloppe un type primitif n java.lang.String n java.util.Date n java.sql.Date
R. Grin JPA page 135
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) Si la cl est gnre automatiquement, le code Java ne doit pas y faire rfrence ; par exemple dans le constructeur de la classe
R. Grin JPA page 136
Types de gnration
AUTO : le type de gnration est choisi par le fournisseur de persistance, selon le SGBD (squence, table,) ; valeur par dfaut SEQUENCE : utilise 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
R. Grin JPA page 137
23
Gnrateurs didentificateurs
Les annotations @SequenceGenerator et @TableGenerator peuvent annoter lidentificateur de lentit ou lentit 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
R. Grin JPA page 139 R. Grin
Exemple de gnrateur
@SequenceGenerator( name = "emp_seq", sequence_name = "emp_seq", allocation_size = 10, initialValue = 600)
JPA
page 140
R. Grin
JPA
page 141
R. Grin
JPA
page 142
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 EclipseLink, Oracle et MySQL (et peuttre 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
R. Grin JPA page 143
Cl composite
Pas recommand, mais une cl primaire peut tre compose de plusieurs colonnes Peut arriver quand la BD existe dj, en particulier quand la classe correspond une table association (association M:N, cas tudi dans la section suivante sur les associations) 2 possibilits : n @IdClass n @EmbeddedId et @Embeddable
R. Grin JPA page 144
24
@EmbeddedId
La classe cl primaire est annot par @Embeddable La cl primaire est reprsente dans lentit par un seul attribut, du type de la classe embeddable et annot par @EmbeddedId 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
R. Grin JPA page 146
@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 ; ses attributs ont les mmes noms et mmes types que les attributs annots @Id dans la classe entit
R. Grin JPA page 148
R. Grin
JPA
page 150
25
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 lattribut (ou les attributs) correspondant, pour que JPA puisse les grer correctement ; par exemple : @ManyToOne private Departement departement
page 151 R. Grin JPA page 152
Associations
R. Grin
JPA
Types utiliser
Le plus souvent Collection sera utilis Set peut tre utile pour liminer les doublons List peut tre utilis pour conserver un ordre mais ncessite quelques prcautions (voir section Complments sur les associations ) Map permet davoir un accs rapide une entit associe par lintermdiaire dune cl
JPA
page 154
Association bidirectionnelle
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
R. Grin
JPA
page 156
26
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, appel aussi bout inverse ) est qualifi par lattribut mappedBy qui donne le nom de lattribut dans le bout propritaire qui correspond la mme association
R. Grin JPA page 157
Exemple
Dans la classe Employe :
@ManyToOne private Departement departement;
R. Grin
JPA
page 158
Annotation @JoinColumn
Cette annotation donne le nom de la colonne cl trangre qui reprsente lassociation dans le modle relationnel Elle doit tre mise du ct propritaire (celui qui contient la cl trangre) Sans cette annotation, le nom est dfini par dfaut : <entit_but>_<cl_primaire_entit_but> par exemple, departement_id
R. Grin JPA page 160
Exemple
@ManyToOne @JoinColumn(name="numero_departement") private Departement departement;
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)
page 161 R. Grin JPA page 162
R. Grin
JPA
27
Exemple
@JoinColumns({ @JoinColumn(name = "n1", referencedColumnName = "c1"), @JoinColumn(name = "n2", referencedColumnName = "c2") })
R. Grin
JPA
page 163
R. Grin
JPA
page 164
Exemple
Dans les associations 1-N, le bout 1 peut comporter ce genre de mthode (dans la classe Departement dune association dpartementemploy) :
public void ajouterEmploye(Employe e) { Departement d = e.getDept(); if (d != null) d.employes.remove(e); this.employes.add(e); employe.setDept(this); }
R. Grin
JPA
page 165
Association 1:1
Annotation @OneToOne Reprsente par une cl trangre ajoute dans la table qui correspond au ct propritaire Exemple :
@OneToOne private Adresse adresse;
R. Grin
JPA
page 168
28
R. Grin
JPA
page 169
Exemple
Voici une partie du code dune entit Parking qui est en association 1-1 avec lentit Employe ; la place de parking dun employ a la mme cl primaire que lemploy Avec PrimaryKeyJoinColumn :
@OneToOne @PrimaryKeyJoinColumn private Employe employe;
Exemple
class Employe { @ManyToOne private Departement departement ... } class Departement { ... @OneToMany(mappedBy = "departement") private List<Employe> employes(); ... }
R. Grin
JPA
page 173
R. Grin
JPA
page 174
29
1:N unidirectionnelle
public class Dept { ... @OneToMany @JoinTable(name="DEPT_EMP", joinColumns=@JoinColumn(name="DEPT_ID"), inverseJoinColumns= @JoinColumn(name="EMP_ID")) private Collection<Employe> employes; ... }
R. Grin JPA page 175
R. Grin
JPA
page 176
Association M:N
Traduite par 1 ou 2 collections (suivant directionnalit) dans les classes qui participent lassociation, annotes par @ManyToMany Le dveloppeur peut choisir le ct propritaire dune association M:N bidirectionnelle ; lautre ct comporte lattribut mappedBy Reprsente par une table association dans la base de donnes relationnelle
R. Grin JPA page 177 R. Grin
Exemple
@ManyToMany private Collection<Projet> projets; @ManyToMany(mappedBy = "projets") private Collection<Employe> employes;
JPA
page 178
@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
R. Grin JPA page 180
30
R. Grin
JPA
page 181
Classe association
Lassociation M:N est traduite par une classe association qui a 2 liens annots @ManyToOne vers les classes qui participent lassociation Selon la directionnalit de lassociation, ces classes peuvent aussi contenir chacune une collection de la classe association, annote par @OneToMany
2 cas
2 possibilits pour cette classe, suivant quelle contient ou non un attribut identificateur (@Id) unique Le plus simple est de navoir quun seul attribut identificateur
R. Grin
JPA
page 183
R. Grin
JPA
page 184
R. Grin
JPA
page 185
R. Grin
JPA
page 186
31
R. Grin
JPA
page 187
R. Grin
JPA
page 188
R. Grin
JPA
page 189
R. Grin
JPA
page 190
Identit drive
JPA 2 prend en compte cette situation avec la notion didentit drive (JPA 1 avait une solution plus complexe et moins portable) Il existe plusieurs variantes qui sont dcrites en dtails dans la spcification de JPA 2 (section 2.4.1.2), selon que les classes qui participent lassociation ont des cls simples ou composes de plusieurs attributs et selon lutilisation de IdClass ou EmbeddedId Pour notre exemple, nous ne verrons ici que la variante avec Embeddedid
R. Grin
JPA
page 191
R. Grin
JPA
page 192
32
Classe Participation
@Entity public class Participation { @EmbeddedId private ParticipationId id; @MapsId("employePK") @ManyToOne private Employe employe; @MapsId("projetPK") @ManyToOne private Projet projet; private String fonction; ... }
R. Grin JPA page 195
R. Grin
JPA
page 196
Participation (constructeurs)
public Participation() { } // Pour JPA public Participation(Employe employe, Projet projet, String fonction) { this.employe = employe; this.projet = projet; employe.getParticipations.add(this); projet.getParticipations.add(this); this.fonction = fonction; }
R. Grin JPA page 198
R. Grin
JPA
page 197
33
R. Grin
JPA
page 199
Exemple
Les employs dun dpartement peuvent tre enregistrs dans une map dont les cls sont les noms des employs (on suppose que 2 employs nont pas le mme nom)
public class Departement { ... @OneToMany(mappedBy = "departement") @MapKey(name = "nom") public Map<String,Employe> getEmployes(){ ... }
R. Grin JPA page 202
R. Grin
JPA
page 201
Autre exemple
La cl doit identifier la valeur dans le contexte de linstance de la classe qui contient la map Les numros de tlphone dun employ sont rangs dans une map dont la cl est le type du numro (mobile, domicile, fixe travail,...)
public class Employe { @OneToMany @MapKeyColumn(name="TYPE_NUMERO") private Map<String,Telephone> tels; ... tels.put("domicile", "0492....");
R. Grin JPA page 203 R. Grin
34
Pas si simple
Maintenir une cohrence automatique des valeurs persistantes nest pas si simple Par exemple, si un objet devient non persistant, faut-il aussi rendre non persistants tous les objets quil a rendu persistants par transitivit ? De plus, le service de persistance doit alors examiner toutes les rfrences des objets qui sont rendus persistants, et ce, de faon rcursive, ce qui peut nuire aux performances
R. Grin JPA page 206
Le choix de JPA
Par dfaut, JPA neffectue pas de persistance par transitivit automatique : rendre persistant un objet ne suffit pas rendre automatiquement et immdiatement persistants tous les objets quil rfrence Comme la cohrence nest pas gre automatiquement, cest le code de lapplication qui se doit de conserver cette cohrence, au moins au moment du commit
R. Grin JPA page 207
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
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, DETACH et MERGE ; ALL correspond toutes ces oprations Par dfaut, aucune opration nest applique transitivement
R. Grin JPA page 210
R. Grin
JPA
page 209
35
Exemples
@OneToMany( cascade = CascadeType.PERSIST) private Collection<Employe> employes; @OneToMany( cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy = "client") private Collection<Facture> factures;
R. Grin
JPA
page 211
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
R. Grin JPA page 213
R. Grin
JPA
page 216
36
Attribut orphanRemoval
Si une annotation @OneToMany a lattribut orphanRemoval "true", les entits supprimes de la collection se verront appliquer lopration remove par le gestionnaire dentit (les donnes correspondantes seront supprimes de la BD) Lannotation @OneToOne peut aussi avoir cet attribut ; la suppression de lorphelin a lieu lorsque la rfrence vers lui est mise null dans lentit qui lui est associe
R. Grin JPA page 218
Attribut orphanRemoval
La suppression a lieu au moment du flush Lattribut orphanRemoval implique cascade=REMOVE
Exemple
@Entity public class Facture { ... @OneToMany(mappedBy="facture", cascade=ALL, orphanRemoval= "true") private Collection<LigneFacture> lignes; ... }
R. Grin
JPA
page 219
R. Grin
JPA
page 220
R. Grin
JPA
page 221
37
@OrderBy
Il faut prciser un ou plusieurs attributs (spars par une virgule) de type basic, qui dterminent lordre Chaque attribut peut tre prcis par ASC ou DESC (ordre ascendant ou descendant) ; ASC par dfaut Si aucun attribut nest prcis, lordre sera celui de la cl primaire (si la collection correspond une association entre entits) ou lordre de la valeur pour les collections dlments de type basic
R. Grin JPA page 223
Exemples
@Entity public class Departement { ... @OneToMany(mappedBy = "departement") @OrderBy("nomEmploye") private List<Employe> employes;
R. Grin
JPA
page 224
@OrderColumn
Cette annotation introduite par JPA 2.0 indique quune colonne dans la BD correspond lordre dune liste Java Cette annotation peut tre ajoute aux associations OneToMany, ManyToMany et aux collections dlments Lannotation doit tre mise du ct de lattribut qui rfrence la liste ordonne ; attention, pour une association 1-N cest donc le ct non propritaire
R. Grin JPA page 226
R. Grin
JPA
page 225
R. Grin
JPA
page 228
38
Exemple
@Entity public class Facture { ... @OneToMany(mappedBy = "facture") @OrderColumn(name = "numero_ligne") private List<LigneCommande> lignes; ... }
R. Grin
JPA
page 229
R. Grin
JPA
page 230
R. Grin
JPA
page 231
R. Grin
JPA
page 232
Stratgies
A ce jour, les implmentations de JPA doivent obligatoirement offrir 2 stratgies pour la traduction de lhritage : n une seule table pour une hirarchie dhritage (SINGLE_TABLE)
n
Hritage
une table par classe ; les tables sont jointes pour reconstituer les donnes (JOINED)
La stratgie une table distincte par classe concrte est seulement optionnelle (TABLE_PER_CLASS)
R. Grin JPA page 233 R. Grin JPA page 234
39
Annotation @Inheritance
Le choix de la stratgie se fait avec lannotation @Inheritance Cest la classe racine de la hirarchie dhritage qui doit tre annote Si on choisit la stratgie par dfaut (SINGLE_TABLE), lannotation est optionnelle : si la classe racine est une entit (annote @Entity) et na pas dannotation @Inheritance, la stratgie dhritage est suppose tre SINGLE_TABLE
R. Grin JPA page 235
Exemple
Dans la classe @Entity racine de la hirarchie ; @Inheritance(strategy= optionnel InheritanceType.SINGLE_TABLE) public abstract class Personne {...} @Entity Employe par dfaut @DiscriminatorValue("E") public class Employe extends Personne { ... }
R. Grin JPA page 237 R. Grin
Nom de la table
Si on choisit la stratgie une seule table pour une arborescence dhritage la table a le nom de la table associe la classe racine de la hirarchie
JPA
page 238
40
Exemple
@Entity @Inheritance @DiscriminatorColumn( name="TRUC", discriminatorType="STRING", length=5) public class Machin { }
Valeur discriminatrice
Chaque classe est diffrencie par une valeur de la colonne discriminatrice Cette valeur est passe en paramtre de lannotation @DiscriminatorValue Par dfaut cette valeur est le nom de lentit (le nom de la classe si pas dattribut name pour @Entity)
R. Grin
JPA
page 241
R. Grin
JPA
page 242
R. Grin
JPA
page 243
Exemple
@Entity @Inheritance(strategy= InheritanceType.JOINED) @DiscriminatorValue("P") public abstract class Personne {...} @Entity @DiscriminatorValue("E") public class Employe extends Personne { ... }
R. Grin JPA page 245
@PrimaryKeyJoinColumn
Par dfaut, la colonne cl trangre a le mme nom que la colonne cl primaire rfrence Si a nest pas le cas, il faut utiliser lannotation @PrimaryKeyJoinColumn( name=<nom colonne cl trangre>) Une annotation @PrimaryKeyJoinColumns peut tre utilise en cas de cl trangre compose de plusieurs colonnes
R. Grin
JPA
page 246
41
Exemple
@Entity @Inheritance(strategy= InheritanceType.TABLE_PER_CLASS) public abstract class Personne {...} @Entity @Table(name=EMPLOYE) public class Employe extends Personne { ... }
R. Grin
JPA
page 248
Entit abstraite
Une classe abstraite peut tre une entit (annote par @Entity) Son tat sera persistant et sera utilis par les sous-classes entits Comme toute entit, elle pourra dsigner le type retour dune requte (query) pour une requte polymorphe
Complments
Lannotation @Entity ne shrite pas Les sous-classes entits dune entit doivent tre annote par @Entity Une entit peut avoir une classe mre qui nest pas une entit ; en ce cas, ltat de cette classe mre ne sera pas persistant
R. Grin
JPA
page 249
R. Grin
JPA
page 250
R. Grin
JPA
page 252
42
Exemple
Si toutes les entits ont des attributs pour enregistrer la date de la dernire modification et le nom de lutilisateur qui a effectu cette modification, il peut tre intressant davoir une classe abstraite Base, mre de toutes les entits qui contient ces attributs Cette classe mre sera annote avec @MappedSuperclass
Code de lexemple
@MappedSuperclass public abstract class Base { @Id @GeneratedValue private Long Id; @Version private Integer version; @ManyToOne private User user; @Temporal(value = TemporalType.TIMESTAMP) private Date dateModif; ... }
R. Grin JPA page 254
R. Grin
JPA
page 253
R. Grin
JPA
page 255
43