Sunteți pe pagina 1din 19

Plan de ce cours

JPA
 Présentation de JPA

(Java Persistence API)


 Entité persistante
 Gestionnaire d’entités

pour Java EE
 Compléments sur les entités : identité,
associations, héritage
 Langage d’interrogation

ITU - Université de Nice Sophia Antipolis  Exceptions


Version O 1.8.2 – 22/2/16  Modifications en volume
Richard Grin  Transaction
 Concurrence
R. Grin JPA page 2

JPA
 Spécification pour la persistance des objets Java
dans une base de données (BD) relationnelle
 ORM, Object-Relational mapping, fait
Présentation de JPA correspondre le monde relationnel et le monde
des objets
 Au-dessus de JDBC
 Utilisable avec Java EE ou avec Java SE

R. Grin JPA page 3 R. Grin JPA page 4

Principales propriétés de JPA Fournisseur de persistance


 Des appels simples permettent de gérer la  L’utilisation de JPA nécessite un fournisseur
persistance, tels que persist(objet) de persistance qui implémente les classes et
pour rendre un objet persistant interfaces de l’API
 Les données de la base sont accédées avec une  EclipseLink est l’implémentation de référence
vision « objet » (pas relationnelle)

R. Grin JPA page 5 R. Grin JPA page 6

1
Entité Exemple d’entité – identificateur
et attributs
 Classe dont les instances peuvent être
persistantes @Entity
 Annotée par @Entity public class Departement { Clé primaire
dans la base –
 « entité » peut aussi désigner une instance de @Id
@GeneratedValue obligatoire
classe entité
private int id; générée
automatiquement
private String nom;
private String lieu;

R. Grin JPA page 7 R. Grin JPA page 8

Exemple d’entité – constructeurs Exemple d’entité – une association


Association inverse
dans classe Employe
public Departement() { } Obligatoire @OneToMany(mappedBy="dept")
private List<Employe> employes =
public Departement(String nom, new ArrayList<>();
String lieu) {
this.nom = nom; public List<Employe> getEmployes() {
this.lieu = lieu; return employes;
} }
public void addEmploye(Employe emp) {
employes.add(emp);
}
R. Grin JPA page 9 R. Grin JPA page 10

Fichiers de configuration XML persistence.xml


 META-INF/persistence.xml : informations <persistence version= "2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence">
sur les connexions aux BDs qui seront <persistence-unit name="employes" 1 unité par BD
utilisées pour conserver les entités transaction-type="JTA">
<jta-data-source>java:app/jdbc/b1</jta-data-source>
<properties> nom JNDI dans le serveur d’application
<property name="javax.persistence.schema-
generation-action" value="create"/> tables créées si besoin
<property name="eclipselink.logging.level"
value="FINE"/>
</properties>
propriété non standard du
</persistence-unit>
fournisseur de persistance
</persistence>

R. Grin JPA page 11 R. Grin JPA page 12

2
Définition d’une source de données Exemple
 Directement dans le serveur d’application @DataSourceDefinition(
 Dans l’application,
name = "java:app/jdbc/b1",
className =
 de façon standard par
"org.apache.derby.jdbc.ClientDataSource",
@DataSourceDefinition (voir TP 3)
portNumber = 1527,
 d’une façon particulière au serveur serverName = "localhost",
d’application (glassfish-resources.xml par user = "APP", password = "APP",
exemple) databaseName = "db1")
@Stateless
public class MonEJB { ... }

R. Grin JPA page 13 R. Grin JPA page 14

Gestionnaire d’entités (EM) Contexte de persistance


 Classe  em.persist(entité)
javax.persistence.EntityManager rend entité persistant  sera gérée par em
 Interlocuteur principal pour le développeur  Toute modification apportée à entité sera
 Fournit les méthodes pour gérer les entités : enregistrée dans la BD par em au moment du
 les rendre persistantes
commit
 L’ensemble des entités gérées par un EM
 les supprimer de la BD
s’appelle un contexte de persistance (CP)
 retrouver leurs valeurs dans la BD

…

R. Grin JPA page 15 R. Grin JPA page 16

Exemple 1 Exemple 2
nom dans persistence.xml public void augmenter(String poste, int prime) {
@Stateless String requete = Que fait cette méthode ?
public class DepartementFacade { "SELECT e FROM Employe e "
@PersistenceContext(unitName = "employes") + " WHERE e.poste = :poste";
private EntityManager em; EM injecté par le container Query q = em.createQuery(requete);
q.setParameter("poste", poste);
public void create(Dept dept) { List<Employe> liste = q.getResultList();
em.persist(dept); for (Employe e : liste) {
dept.setLieu("Paris"); enregistré dans la BD ? e.setSalaire(e.getSalaire() + prime);
}
} Oui Est-ce que les augmentations
}
... seront dans la base de données ?
}
Transaction démarrée
au début de la méthode Pourquoi ? Oui, car les employés récupérés dans la BD
et fermée à la fin sont ajoutés par em au contexte de persistance
R. Grin JPA page 17 R. Grin JPA page 18

3
Conditions pour une classe entité
 Constructeur sans paramètre protected ou
public
Attribut qui représente la clé primaire dans la BD
Entités

 Pas final
 Méthodes ou champs persistants pas final

R. Grin JPA page 19 R. Grin JPA page 20

Types d’accès à une valeur persistante Exemple


 JPA peut accéder à la valeur d’un attribut de 2  Accès par champ :
façons @Id
 par la variable d’instance ;
private int id;
accès « par champ »  Accès par propriété :
@Id
 par les accesseurs (getter ou setter) ;
public int getId() {
accès « par propriété » ...
}

R. Grin JPA page 21 R. Grin JPA page 22

Quel type d’accès choisir ? Attributs persistants


 L’accès par propriété oblige à ajouter des getters  Par défaut, tous les attributs d’une entité sont
et des setters pour tous les attributs persistants
 Exception : attribut avec un champ
 Choisir plutôt l’accès par champ
transient ou annoté par @Transient

R. Grin JPA page 23 R. Grin JPA page 24

4
Types persistants Types « basic »
 Un attribut persistant peut être d’un des types  Types primitifs (int, double,…) ou
suivants : enveloppes de type primitifs (Integer,…)
 « basic »  String, BigInteger, BigDecimal
 « Embeddable »  Date, Calendar, Time, Timestamp
 collection d’éléments de type « basic » ou  Énumérations
Embeddable  Tableaux de byte, Byte, char, Character
 Plus généralement Serializable
(sauvegardé comme un tout dans la base)

R. Grin JPA page 25 R. Grin JPA page 26

Cycle de vie d’une instance d’entité Table de la base de données


 L’instance peut être  Dans les cas simples, une classe  une table
 nouvelle : créée mais pas gérée par un EM  nom de la table = nom de la classe

 gérée par un EM (méthode persist, ou  noms des colonnes = noms des attributs
instance récupérée dans la BD par une  Par exemple, la classe Departement
requête) correspond à la table Departement avec les
 détachée : a une identité dans la BD mais colonnes id, nom, lieu
n’est plus gérée par un EM  Convention plutôt que configuration pour JPA
 supprimée : gérée par un EM ; données
supprimées dans la BD au commit
(méthode remove)
R. Grin JPA page 27 R. Grin JPA page 28

Exemple Classe Embeddable


 @Entity  Classe persistante dont les données
public class Departement {  n’ont pas d’identité dans la BD
instances sauvegardées dans la table
 sont insérées dans une table associée à
Departement
une entité
 @Entity
@Table(name = "DEPT")
public class Departement {

R. Grin JPA page 29 R. Grin JPA page 30

5
Exemple
@Embeddable
public class Adresse {
private int numero;

Gestionnaire d’entités
private String rue;
private String ville;

(Entity Manager)
. . .
}
@Entity
public class Employe {
@Embedded optionnel
private Adresse adresse;
...
}
R. Grin JPA page 31 R. Grin JPA page 32

2 types d’EM dans EM géré par l’application


un serveur d’application Fabrique d’EM injectée
@Stateful
par le container
Géré par l’application : créé par l’application à
public class DeptManager {

@PersistenceUnit(unitName = "employes")
partir d’une fabrique d’EM injectée private EntityManagerFactory emf;
 Géré par le container : injecté par le serveur private EntityManager em;
d’application private Departement dept;

public void init(int deptId) {


em = emf.createEntityManager();
dept = em.find(Departement.class, deptId);
}
...

R. Grin JPA page 33 R. Grin JPA page 34

2 types d’EM géré par le container Portée transaction

 Le type d’EM dépend de la relation de l’EM @Stateless


EM injecté par le container
avec le CP et de la durée de vie du CP
public class DeptFacade {
@PersistenceContext(unitName = "employes")
 EM de portée transaction : le CP ne dure private EntityManager em;
que le temps de la transaction et il peut être Optionnel si une seule
lié à plusieurs EM public void create(Dept dept) { unité de persistance
em.persist(dept);
 EM étendu (ne peut exister que dans un }
CP ne dure que le temps
EJB stateful) : le CP est lié à un seul EM ; il ...
de la transaction
peut exister après le commit de la }
transaction

R. Grin JPA page 35 R. Grin JPA page 36

6
Propagation de contexte EM étendu
 Avec un EM de portée transaction, à chaque @Stateful
opération JPA, l’EM regarde si un CP est déjà public class Caddy {
attaché à la transaction @PersistenceContext(type=EXTENDED)
EntityManager em;
 Si c’est le cas, ce CP est utilisé par l’EM, sinon Même CP conservé
le container en crée un nouveau et l’attache à ...
pendant plusieurs transactions
la transaction }

 Permet à plusieurs EMs d’utiliser le même CP  Permet d’établir une conversation longue
pendant une transaction entière entre l’utilisateur et la BD, sans avoir à gérer
des entités détachées (le contexte reste
ouvert entre les transactions)
R. Grin JPA page 37 R. Grin JPA page 38

Choix du type d’EM Méthodes de EntityManager


 void persist(Object entité)
 Plus simple de le faire gérer par le container  <T> T merge(T entité)
(propagation du CP, pas besoin de le fermer)
 void remove(Object entité)
 Le plus souvent l’EM est de portée transaction
 <T> T find(Class<T> classeEntité,
Object cléPrimaire)
 void flush()
 void lock(Object entité,
LockModeType lockMode)
 void refresh(Object entité)
 void close()
R. Grin JPA page 39 R. Grin JPA page 40

Méthodes de EntityManager flush()


 void clear()
 void detach(Object entity)
 Enregistre dans la BD les modifications
effectuées sur les entités d’un contexte de
 Query createQuery(String requête)
persistance
 Query createNamedQuery(String nom)
 L’EM lance les commandes SQL pour
 Query createNativeQuery(String modifier la BD (INSERT, UPDATE ou
requête) DELETE)
 Automatiquement effectué à chaque commit

R. Grin JPA page 41 R. Grin JPA page 42

7
refresh(entité) Contexte de persistance - cache
 Données de la BD sont copiées dans l’entité  Un CP est un cache pour les accès à la BD
 Pour avoir la dernière version de l’entité  find ou query ramènent les données du
cache
 Bénéfice : meilleures performances
 Attention, les données du cache ne tiennent
pas compte des modifications effectuées
sans passer par l’EM
 Peut poser des problèmes ; un refresh peut
être la solution

R. Grin JPA page 43 R. Grin JPA page 44

Entité détachée merge(a)


 Une entité gérée par un EM peut être  Attention, merge(a) n’attache pas a
détachée de son contexte de persistance (par  Retourne une entité gérée qui a la même
exemple si l’EM est fermé ou l’entité envoyée identité dans la BD que a, mais qui n’est pas le
« au loin ») même objet (sauf si l’objet était déjà géré)
 Cette entité détachée peut être modifiée  Après un merge, si l’application utilise les

 Pour que ces modifications soient données de a il faut écrire ce type de code :
enregistrées dans la BD, il est nécessaire de a = em.merge(a);
rattacher l’entité à un EM par la méthode
merge

R. Grin JPA page 45 R. Grin JPA page 46

merge – une erreur à ne pas faire Différence entre persist et merge


 Ajouter un employé à dept dans la base :  persist sert pour les entités dont les
em.merge(dept); Quel est le données ne sont pas déjà dans la base :
dept.addEmploye(emp); problème ?  traduit par un INSERT
 L’ajout du nouvel employé ne sera pas  si l’entité a un id qui correspond à une
enregistré dans la base car l’objet référencé ligne de la base, une
par dept n’est pas géré ; le bon code : EntityExistsException est levée
dept = em.merge(dept);  Au contraire merge sert le plus souvent pour
dept.addEmploye(emp); les entités qui correspondent à des données
déjà dans la base et il est alors traduit par un
UPDATE
R. Grin JPA page 47 R. Grin JPA page 48

8
Clé primaire
 L’attribut, annoté @Id correspond à la clé
primaire dans la table associée
 Ne jamais le modifier dès que l’entité

Identité des entités représente des données de la base

R. Grin JPA page 49 R. Grin JPA page 50

Type de la clé primaire Génération automatique de clé


 Type primitif Java
 Pour les clés de type nombre entier
 Classe qui enveloppe un type primitif
 @GeneratedValue indique que la clé
 java.lang.String
primaire sera générée par le SGBD
 (java.util.Date)
 Cette annotation peut avoir un attribut
 (java.sql.Date) strategy qui indique comment la clé sera
générée

R. Grin JPA page 51 R. Grin JPA page 52

Exemple Clé composite


@Id  Pas recommandé, mais une clé primaire peut
@GeneratedValue( être composée de plusieurs colonnes
strategy = GenerationType.SEQUENCE,  Peut arriver quand la BD existe déjà, en
generator = "EMP_SEQ") particulier quand la classe correspond à une
private long id; table association (association M:N)
 2 possibilités :
 @EmbeddedId et @Embeddable

 @IdClass

R. Grin JPA page 53 R. Grin JPA page 54

9
 Faire TP 3

Associations

R. Grin JPA page 55 R. Grin JPA page 56

Rappels Association bidirectionnelle - JPA


 Types d’association entre entités :  Le développeur est responsable de la gestion
 1-1, 1-N, N-1, M-N correcte des 2 bouts de l’association
 uni ou bidirectionnelle  Pour faciliter la gestion des 2 bouts, il est

 Exemples : association entre


commode d’ajouter une méthode qui effectue
tout le travail
 une entreprise et ses employés

 les cours et les étudiants

R. Grin JPA page 57 R. Grin JPA page 58

Exemple Bout propriétaire


 Dans les associations 1-N, le bout « 1 » peut
comporter ce genre de méthode :  Un des 2 bouts est dit propriétaire de
public void ajouterEmploye(Employe e) { l’association ; celui qui correspond à la table
Departement d = e.getDept(); qui contient la clé étrangère
if (d != null)  Pour les associations 1 – N, c’est le bout … ?
d.employes.remove(e);
this.employes.add(e); N
Dans quelle classe
e.setDept(this);  L’autre bout contient l’attribut mappedBy qui
est ce code ?
} donne le nom de l’attribut dans le bout
propriétaire

R. Grin JPA page 59 R. Grin JPA page 60

10
Exemple Valeurs par défaut
 Dans la classe Employe :  Si une valeur par défaut ne convient pas,
@ManyToOne ajouter une annotation dans le bout
private Departement departement; propriétaire
 Dans la classe Departement :  Par exemple, pour indiquer le nom de la
@OneToMany(mappedBy = "departement") colonne clé étrangère :
private Collection<Employe> employes;
@ManyToOne
Quel est le bout propriétaire ? Classe Employe @JoinColumn(name="DEPT")
private Departement departement;
Dans quelle table sera la clé étrangère ? Table EMPLOYE

Nom de la colonne clé étrangère : DEPARTEMENT_ID Que signifie l’annotation @JoinColumn ?

R. Grin JPA page 61 R. Grin JPA page 62

Association M:N Exemple Dans quelle classe ?

 Traduite par 1 ou 2 collections annotées par @ManyToMany


@ManyToMany private Collection<Projet> projets;

 Pourquoi « 1 ou 2 » ? @ManyToMany(mappedBy = "projets")


 On peut choisir le bout propriétaire private Collection<Employe> employes;

Quel est le bout propriétaire ?


Dans quelle classe ?
Dans quelle table sera la clé étrangère ?

R. Grin JPA page 63 R. Grin JPA page 64

Association M:N avec information Classe association


portée par l’association
 Association M:N traduite par une classe
association
 Exemple :
Association entre les employés et les projets ;  Chaque classe qui participe à l’association
un employé a une fonction dans chaque peut avoir une collection d’objets de la classe
projet auquel il participe association (suivant directionnalité)
 2 possibilités pour la classe association :
 un attribut identificateur (@Id) unique (le

plus simple)
 un attribut identificateur par classe
participant à l’association
R. Grin JPA page 65 R. Grin JPA page 66

11
Code classe association (début) Code classe association (fin)
public Participation() { }
@Entity
public class Participation {
public Participation(Employe employe,
@Id @GeneratedValue
Projet projet, String fonction) {
private int id;
this.employe = employe;
@ManyToOne
private Employe employe; this.projet = projet;
@ManyToOne this.fonction = fonction;
private Projet projet; }
private String fonction; // Accesseurs pour employe et projet
...

R. Grin JPA page 67 R. Grin JPA page 68

Pas de persistance par transitivité Cohérence des données


automatique avec JPA
 Soit une classe Departement qui contient
 Par défaut, JPA n’effectue pas une collection d’Employe
automatiquement la persistance par
transitivité :  Si un département est rendu persistant et si un
rendre persistant un département ne suffit des employés du département est non
persistant, une IllegalStateException
pas à rendre persistants ses employés
est lancée au moment du commit
 La cohérence des données de la BD repose
 L’attribut cascade des associations peut
donc sur le code de l’application
simplifier le code

R. Grin JPA page 69 R. Grin JPA page 70

Cascade Récupération des entités associées


 Les opérations persist, remove, refresh,  Lorsqu’une entité est récupérée depuis la BD
merge, detach peuvent être transmises par (Query ou find), est-ce que les entités
transitivité à l’autre bout d’une association associées sont aussi récupérées ?
 Exemple :  Si elles sont récupérées, est-ce que les entités
@OneToMany( associées à ces entités doivent elles aussi
cascade = { CascadeType.PERSIST, être récupérées ?
CascadeType.MERGE },
mappedBy = "client")  Le risque est de récupérer un très grand
private Collection<Facture> factures; nombre d’entités inutiles

Dans quelle classe est ce code ? Qu’indique l’attribut cascade ?


R. Grin JPA page 71 R. Grin JPA page 72

12
EAGER ou LAZY Récupération tardive
 JPA laisse le choix de récupérer ou non
 Supposons une association en mode lazy
immédiatement les entités associées
entre un département et ses employés
 Mode EAGER : les données associées sont
 On récupère un département
récupérées immédiatement
 Plus tard on veut avoir le nom d’un employé
 Mode LAZY : les données associées ne sont
 Cet employé est alors récupéré par l’EM si
récupérées que lorsque c’est vraiment
nécessaire (lazy loading) l’entité département n’est pas alors détachée
(automatique, on n’a rien à faire)
 Et si le département est détaché ?
 Il faut faire un merge préalable du département

R. Grin JPA page 73 R. Grin JPA page 74

Mode de récupération par défaut Indiquer le type de récupération


des entités associées des entités associées
 Mode EAGER pour les associations OneToOne  L’attribut fetch permet de modifier le
et ManyToOne comportement par défaut
 @OneToMany(mappedBy = "departement",
 Mode LAZY pour les associations OneToMany
fetch = FetchType.EAGER)
et ManyToMany private Collection<Employe> employes;

Vous voyez une raison pour ce choix ?

R. Grin JPA page 75 R. Grin JPA page 76

Stratégies
 2 stratégies pour la traduction de l’héritage :
 une seule table pour une hiérarchie
d’héritage (SINGLE_TABLE) ; par défaut
Héritage  une table par classe ; les tables sont jointes
pour reconstituer les données (JOINED)
 La stratégie « une table distincte par classe
concrète » est optionnelle
(TABLE_PER_CLASS)

R. Grin JPA page 77 R. Grin JPA page 78

13
Toutes les classes traduites Exemple « 1 table par hiérarchie »
par une seule table Dans la classe
@Entity racine de la
@Inheritance(strategy = hiérarchie ;
InheritanceType.SINGLE_TABLE) optionnel
public abstract class Personne {...}

@Entity « Employe » par défaut


@DiscriminatorValue("E")
public class Employe extends Personne {
...
}
Pour différencier les
types de personnes
R. Grin JPA page 79 R. Grin JPA page 80

Une table par classe Préservation de l’identité


Colonne
discriminatrice

Clé étrangère
et primaire

R. Grin JPA page 81 R. Grin JPA page 82

Exemple
@Entity
@Inheritance(strategy =

Requêtes – JPQL
InheritanceType.JOINED)
public abstract class Personne {...}

@Entity
Java Persistence Query Language
@DiscriminatorValue("E")
public class Employe extends Personne {
...
}

R. Grin JPA page 83 R. Grin JPA page 84

14
IMPORTANT Chercher par identité
 Cette section concerne les entités retrouvées  find retrouve une entité en donnant son
en interrogeant la base de données identificateur dans la BD :
Departement dept =
 Toutes ces entités sont automatiquement em.find(Departement.class, 10);
gérées par le gestionnaire d’entités
 Les modifications apportées à ces entités
seront enregistrées au prochain commit

R. Grin JPA page 85 R. Grin JPA page 86

Étapes pour récupérer des données


 Il est possible de rechercher des données sur 1. Décrire ce qui est recherché (langage JPQL)
des critères plus complexes que la simple 2. Créer une instance de type Query
identité 3. Initialiser la requête (paramètres, pagination)
4. Lancer l’exécution de la requête
String s = "select e from Employe as e";
Query query = em.createQuery(s);
List<Employe> listeEmployes =
(List<Employe>)query.getResultList();

cast obligatoire
R. Grin JPA page 87 R. Grin JPA page 88

Exemple plus complexe Langage JPQL


String q = "select e from Employe as e "
 Java Persistence Query Language décrit ce qui
+ "where e.departement.numero = :numero";
est recherché en utilisant le modèle objet (pas
Query query = em.createQuery(q);
le modèle relationnel)
query.setParameter("numero", 10);
query.setMaxResults(30);  Les seules classes qui peuvent être utilisées

for (int i = 0; i < 5; i++) { sont les entités et les Embeddable


query.setFirstResult(30 * i);
List<Employe> listeEmployes =
(List<Employe>)query.getResultList();
... // Affichage page numéro i + 1
}
R. Grin JPA page 89 R. Grin JPA page 90

15
Exemples de requêtes Obtenir le résultat de la requête
Alias de classe obligatoire
 select e from Employe e  Résultat = une seule valeur ou entité :
 select e.nom, e.salaire from Employe e Object getSingleResult()
 select e from Employe e  Résultat = plusieurs valeurs ou entités :
where e.departement.nom = 'Direction' List getResultList()
 select d.nom, avg(e.salaire)
from Departement d join d.employes e
group by d.nom
having count(d.nom) > 5

R. Grin JPA page 91 R. Grin JPA page 92

Type d’un élément du résultat Exemple


texte = "select e.nom, e.salaire "
 Le type d’un élément du résultat est + " from Employe as e";
 Object si la clause select ne comporte
query = em.createQuery(texte);
List<Object[]> liste =
qu’une seule expression
(List<Object[]>)query.getResultList();
 Object[] sinon
for (Object[] info : liste) {
System.out.println(info[0] + " gagne "
+ info[1]);
}

R. Grin JPA page 93 R. Grin JPA page 94

Types de requête Exemple de requête nommée


@Entity
 Requête dynamique : texte donné en
@NamedQuery (
paramètre de createQuery
name = "employe.findNomsEmpsDept",
 Requête nommée : texte statique donné dans query = "select e.nom from Employe as e
une annotation d’une entité ; le nom est passé where upper(e.departement.nom) = :nomDept"
en paramètre de createNamedQuery )
 Requête native (ou SQL) particulière à un public class Employe extends Personne {
SGBD : requête SQL avec tables et colonnes ...
(pas classes et attributs) ;
createNativeQuery Query q = em.createNamedQuery(
"employe.findNomsEmpsDept");

R. Grin JPA page 95 R. Grin JPA page 96

16
Exemples de paramètres Clauses d’un select
 Query query = em.createQuery(  select
"select e from Employe as e " JPQL permet les sous-requêtes
+ "where e.nom = ?1");
 from
et même les sous-requêtes
query.setParameter(1, "Dupond");  where
synchronisées
 Query query = em.createQuery(  group by
"select e from Employe as e "
 having
+ "where e.nom = :nom");
query.setParameter("nom", "Dupond");  order by

R. Grin JPA page 97 R. Grin JPA page 98

Navigation Règles pour les


expressions de chemin
 Il est possible de suivre le chemin
correspondant à une association avec la  Une navigation peut être chaînée à une
notation « pointée » navigation précédente si la navigation
 Si e alias pour Employe,
précédente ne donne qu’une seule entité
(OneToOne ou ManyToOne)
 « e.departement » désigne le
 select e.nom,
département d’un employé e.departement.nom,
 « e.projets » désigne les projets e.superieur.departement.nom
auxquels participe un employé from Employe e

R. Grin JPA page 99 R. Grin JPA page 100

Contre-exemple Jointure
 « d.employes.nom » est interdit car  Interne (jointure standard join)
d.employes est une collection
 Externe (left outer join)
 Pour avoir les noms des employés d’un
 Avec récupération de données en mémoire
département, il faut une jointure : (join fetch) ; pour éviter le problème des
select e.nom
from Departement d « N +1 selects »
join d.employes e
where d.nom = 'Direction'

R. Grin JPA page 101 R. Grin JPA page 102

17
join fetch Fonctions
 Évite le problème des « N + 1 selects »  Pour les chaînes de caractères : concat,
 select e substring, trim, lower, upper, length,
from Employe as e locate
join fetch e.participations  Arithmétique : abs, sqrt, mod, size
 Les participations sont créées en même temps  Temporelles : current_date,
que les employés (mais pas retournées par le current_time, current_timestamp
select)
 Fonctions de regroupement : count, max, min,
 L’instruction avg
employe.getParticipations()
 case (semblable CASE de SQL)
ne nécessitera pas d’accès à la base

R. Grin JPA page 103 R. Grin JPA page 104

API « criteria »
 Tout ce qui peut être fait avec JPQL peut l’être
avec cette API
 Les requêtes JPQL sont des String qui
peuvent contenir des erreurs (par exemple le Opération de modification
nom d’une classe qui n’existe pas) en volume
 L’avantage de l’API « critères » est que les
requêtes peuvent être vérifiées à la compilation
 L’inconvénient est que le code est un peu plus
complexe à écrire, et sans doute moins lisible

R. Grin JPA page 105 R. Grin JPA page 106

Utilité Exemple
String ordre =
 Augmenter les 10 000 employés de 5% "update Employe e " +
 Une solution : " set e.salaire = e.salaire * 1.05";
Query q = em.createQuery(ordre);
1. Créer toutes les entités « Employe » en
int nbEntitesModif = q.executeUpdate();
lisant les données dans la base
2. Modifier le salaire de chaque entité

3. Enregistrer ces modifications dans la base

 Mauvaise solution ! JPQL permet de modifier


les données de la base directement, sans
créer les entités correspondantes

R. Grin JPA page 107 R. Grin JPA page 108

18
Gestion de la concurrence
 Par défaut, les problèmes d’accès concurrents
sont gérés avec une stratégie optimiste :
 on pense qu’aucune autre transaction ne

Concurrence modifiera les données sur lesquelles on va


travailler
 donc aucun blocage n’est effectué dans la
base de données
 au moment du commit, vérifications pour
voir si on avait raison d’être optimiste
 si on avait tort, rollback de la transaction

R. Grin JPA page 109 R. Grin JPA page 110

@Version lock(A, mode)


 Pour savoir si l’état d’une entité a été modifié
 Protège une entité contre les accès
entre 2 moments différents, on utilise un
concurrents pour les cas où la protection
numéro de version enregistré dans la base
offerte par défaut ne suffit pas
 Ce numéro est incrémenté automatiquement
 Permet en particulier d’effectuer un blocage
par JPA à chaque modification
pessimiste (blocage dans la base)
 Ne doit jamais être modifié par l’application
 Les méthodes find et refresh de
 Exemple : EntityManager ont une variante qui permet
@Version
de bloquer les données liées aux entités
private int version;
retrouvées ou rafraichies

R. Grin JPA page 111 R. Grin JPA page 112

Concurrence et entité détachée


 Une entité est détachée de son EM
 Elle est modifiée
 Quand elle est rattachée à un EM, l’EM vérifie
au moment du commit que le numéro de
version n’a pas changé
 Si le numéro a changé, une
OptimisticLockException est levée

R. Grin JPA page 113

19

S-ar putea să vă placă și