Vous êtes sur la page 1sur 20
JPA 2.0 (Java Persistence API) pour Java EE 6 Université de Nice - Sophia Antipolis Version
JPA 2.0
(Java Persistence API)
pour Java EE 6
Université de Nice - Sophia Antipolis
Version Oral 1.1 – 01/10/13
Richard Grin
Présentation de JPA R. Grin JPA page 3
Présentation de JPA
R. Grin
JPA
page 3
 

Plan de ce cours

Présentation de JPA Entité persistante Gestionnaire d’entités

 

Compléments sur les entités : identité, associations, héritage

Langage d’interrogation Exceptions Modifications en volume Transaction Concurrence

 
  • R. Grin

JPA

page 2

 
 

JPA

Spécification pour la persistance des objets Java dans une BD relationnelle

Peut aussi être utilisé par une application autonome, en dehors de tout serveur d’application

  • R. Grin

JPA

page 4

L’utilisation de JPA nécessite un fournisseur de persistance qui implémente les classes et méthodes de l’API

Fournisseur de persistance

EclipseLink est l’implémentation de référence

page 5

  • R. Grin

JPA

« entité » peut aussi désigner une instance de classe entité

Classe dont les instances peuvent être persistantes

Annotée par @Entity

Entité

page 6

  • R. Grin

JPA

Exemple d’entité – identificateur et attributs @Entity public class Departement { @Id @GeneratedValue private int id;
Exemple d’entité – identificateur
et attributs
@Entity
public class Departement {
@Id
@GeneratedValue
private int id;
private String nom;
private String lieu;
Clé primaire
dans la base –
obligatoire
générée
automatiquement
R. Grin
JPA
page 7
Exemple d’entité – constructeurs /** * Constructeur sans paramètre obligatoire */ public Departement() { } public
Exemple d’entité – constructeurs
/**
* Constructeur sans paramètre obligatoire
*/
public Departement() { }
public Departement(String nom,
String lieu) {
this.nom = nom;
this.lieu = lieu;
}
R. Grin
JPA
page 8
Exemple d’entité – une association Association inverse dans classe Employe @OneToMany(mappedBy="dept") private Collection<Employe> employes = new
Exemple d’entité – une association
Association inverse
dans classe Employe
@OneToMany(mappedBy="dept")
private Collection<Employe> employes =
new ArrayList<>();
public Collection<Employe> getEmployes() {
return employes;
}
public void addEmploye(Employe emp) {
employes.add(emp);
}
R. Grin
JPA
page 9

Annotations peuvent être remplacées par des fichiers de configuration XML Fichiers XML l’emportent sur les annotations

JPA

  • R. Grin

page 10

META-INF/persistence.xml contient les informations pour obtenir une connexion à la BD (une unité de persistance par base de données)

Fichiers de configuration XML

persistence.xml <persistence version= "2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"> <persistence-unit name="employes" transaction-type="JTA"> <provider>org.eclipse.jpa.PersistenceProvider </provider> <jta-data-source>jdbc/formation</jta-data-source> <properties> <property name="javax.persistence.schema- generation-action" value="create"/>
persistence.xml
<persistence version= "2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence">
<persistence-unit name="employes"
transaction-type="JTA">
<provider>org.eclipse.jpa.PersistenceProvider
</provider>
<jta-data-source>jdbc/formation</jta-data-source>
<properties>
<property name="javax.persistence.schema-
generation-action" value="create"/>
<property name="eclipselink.logging.level"
value="FINE"/>
</properties>
</persistence-unit>
</persistence>
R. Grin
JPA
page 11

JPA

  • R. Grin

page 12

Classe javax.persistence.EntityManager Interlocuteur principal pour le développeur Fournit les méthodes pour gérer les entités :

n les rendre persistantes n les supprimer de la BD n retrouver leurs valeurs dans la BD n

Gestionnaire d’entités (EM)

Contexte de persistance em.persist(objet) rend « persistant » objet ⇔ il sera géré par em Toute
Contexte de persistance
em.persist(objet) rend « persistant »
objet ⇔ il sera géré par em
Toute modification apportée à objet sera
enregistrée dans la BD par em au moment du
commit
L’ensemble des entités gérées par un EM
s’appelle un contexte de persistance (CP)
Dans un CP il ne peut exister 2 entités
différentes qui représentent des données
identiques dans la BD
R. Grin
JPA
page 13
Exemple 1 @Stateless public class DeptFacade { @PersistenceContext(unitName = "employes") private EntityManager em; EM injecté par
Exemple 1
@Stateless
public class DeptFacade {
@PersistenceContext(unitName = "employes")
private EntityManager em;
EM injecté par le container
public void create(String nom, String lieu) {
Dept dept = new Dept(nom, lieu);
em.persist(dept);
enregistré dans la BD
dept.setLieu("Paris");
}
...
}
Transaction démarrée
au début de la méthode
et fermée à la fin
R. Grin
JPA
page 14
Exemple 2 public void augmenter(String poste, int prime) { String queryString = "SELECT e FROM Employe
Exemple 2
public void augmenter(String poste, int prime) {
String queryString =
"SELECT e FROM Employe e "
+ " WHERE e.poste = :poste";
Query q = em.createQuery(queryString);
q.setParameter("poste", poste);
List<Employe> liste = q.getResultList();
for (Employe e : liste) {
e.setSalaire(e.getSalaire() + prime);
}
}
Est-ce que les augmentations
seront dans la base de données ?
Oui, car les employés récupérés dans la BD
sont ajoutés par em au contexte de persistance
R. Grin
JPA
page 15
Entités R. Grin JPA page 16
Entités
R. Grin
JPA
page 16

Constructeur sans paramètre protected ou public

JPA

  • R. Grin

page 17

Attribut qui représente la clé primaire dans la BD Pas final

Aucune méthode ou champ persistant ne doit être final

Conditions pour une classe entité

JPA

  • R. Grin

page 18

Le fournisseur de persistance peut accéder à la valeur d’un attribut de 2 façons

n par les accesseurs (getter ou setter) ; c’est l’accès « par propriété »

n directement à la variable d’instance ; c’est l’accès « par champ »

Si l’accès se fait par propriété, les getter et setter doivent être protected ou public

Types d’accès à une valeur persistante

Exemple Accès par champ : @Id private int id; Accès par propriété : @Id public int
Exemple
Accès par champ :
@Id
private int id;
Accès par propriété :
@Id
public int getId() {
}
R. Grin
JPA
page 19

JPA

  • R. Grin

page 20

Conseillé de choisir plutôt l’accès par champ

Quel type d’accès choisir ?

L’accès par propriété oblige à ajouter des getters et des setters pour tous les attributs

JPA

  • R. Grin

Attributs persistants

page 21

Exception : attribut avec un champ transient ou annoté par @Transient

Par défaut, tous les attributs d’une entité sont persistants

JPA

page 22

  • R. Grin

n type

« basic »

n type « Embeddable »

Types persistants

Un attribut peut être d’un des types suivants :

n collection d’éléments de type « basic » ou Embeddable

JPA

  • R. Grin

page 23

Types « basic »

Types primitifs (int, double,…) String, BigInteger, BigDecimal, enveloppes de type primitifs (Integer,…) Date, Calendar, Time, Timestamp Énumérations Tableaux de byte, Byte, char, Character

Plus généralement Serializable (sauvegardé comme un tout dans la base)

JPA

  • R. Grin

page 24

récupérée dans la BD par une requête)

Cycle de vie d’une instance d’entité

n supprimée : gérée par un EM ; données supprimées dans la BD au commit (méthode remove)

L’instance peut être n nouvelle : créée mais pas gérée par un EM

n gérée par un EM ; elle a une identité dans la BD (méthode persist, ou instance

n détachée : a une identité dans la BD mais n’est plus gérée par un EM

page 25

  • R. Grin

JPA

Dans les cas simples, une classe une table n nom de la table = nom de la classe n noms des colonnes = noms des attributs Par exemple, la classe Departement correspond à la table Departement avec les colonnes id, nom, lieu

Les tables de la base de données

page 26

  • R. Grin

JPA

Mapping « JPA » par défaut pour les classes entités

Ajouter des annotations seulement si les valeurs par défaut ne conviennent pas

Configuration « par exception »

Exemple @Entity public class Departement { instances sauvegardées dans la table Departement @Entity @Table(name = "dept")
Exemple
@Entity
public class Departement {
instances sauvegardées dans la table
Departement
@Entity
@Table(name = "dept")
public class Departement {
R. Grin
JPA
page 27
Exemple @Embeddable public class Adresse { private int numero; private String rue; private String ville; .
Exemple
@Embeddable
public class Adresse {
private int numero;
private String rue;
private String ville;
.
.
.
}
@Entity
public class Employe {
@Embedded
optionnel
private Adresse adresse;
...
}
R. Grin
JPA
page 29

Classe Embeddable

Classe persistante dont les données n n’ont pas d’identité dans la BD

n sont insérées dans une table associée à une entité

Grin

  • R. JPA

page 28

 

Gestionnaire d’entités

(Entity Manager), EM

Grin

  • R. JPA

page 30

Sans serveur d’application L’application décide de la durée de vie d’un EM Création d’un EM :
Sans serveur d’application
L’application décide de la durée de vie d’un EM
Création d’un EM :
EntityManagerFactory emf =
Persistence.
createEntityManagerFactory("employes");
EntityManager em =
emf.createEntityManager();
Fermeture de l’EM (plus possible de l’utiliser
ensuite) : em.close();
R. Grin
JPA
page 31

Géré par l’application : créé par l’application à partir d’une fabrique d’EM injectée

JPA

  • R. Grin

page 32

Géré par le container : injecté par le serveur d’application

2 types d’EM dans un serveur d’application

Géré par l’application @Stateless public class DeptFacade { Fabrique d’EM injectée par le container @PersistenceUnit(unitName =
Géré par l’application
@Stateless
public class DeptFacade {
Fabrique d’EM injectée
par le container
@PersistenceUnit(unitName = "employes")
private EntityManagerFactory emf;
public void create(Dept dept) {
EntityManager em;
try {
em = emf.createEntityManager();
em.persist(dept);
} finally {
if (em != null) { em.close(); }
}
Rappel : commit
...
automatique à la fin de
R. Grin
JPA
la méthode
page 33

JPA

  • R. Grin

page 34

2 types d’EM géré par le container :

n EM de portée transaction n EM étendu

2 types d’EM géré par le container

La différence vient de la relation de l’EM avec le contexte de persistance

Portée transaction @Stateless public class DeptFacade { EM injecté par le container @PersistenceContext(unitName = "employes") private
Portée transaction
@Stateless
public class DeptFacade {
EM injecté par le container
@PersistenceContext(unitName = "employes")
private EntityManager em;
public void create(String nom, String lieu) {
Dept dept = new Dept(nom, lieu);
em.persist(dept);
}
CP ne dure que le temps
de la transaction
...
}
R. Grin
JPA
page 35

Permet à plusieurs EMs d’utiliser le même CP pendant une transaction

Si c’est le cas, ce CP est utilisé par l’EM, sinon le container en crée un nouveau et l’attache à la transaction

JPA

  • R. Grin

page 36

Propagation de contexte

Quand un EM est injecté, le container regarde si un CP est attaché à la transaction

EM étendu @Stateful public class CaddyImpl implements Caddy { @PersistenceContext(type=EXTENDED) EntityManager em; ... Même CP conservé
EM étendu
@Stateful
public class CaddyImpl implements Caddy {
@PersistenceContext(type=EXTENDED)
EntityManager em;
...
Même CP conservé
pendant plusieurs transactions
}
R. Grin
JPA
page 37

JPA

  • R. Grin

page 38

Choix du type d’EM

Plus simple de le faire gérer par le container (propagation des transactions, pas besoin de le fermer)

void persist(Object entité) <T> T merge(T entité) void remove(Object entité) <T> T find(Class<T> classeEntité, Object cléPrimaire) void flush() void lock(Object entité, LockModeType lockMode) void refresh(Object entité) void close()

JPA

  • R. Grin

page 39

Méthodes de EntityManager

JPA

  • R. Grin

page 40

Query createQuery(String requête) Query createNamedQuery(String nom) Query createNativeQuery(String requête)

Méthodes de EntityManager

JPA

  • R. Grin

page 41

flush

L’EM lance les commandes SQL adaptées pour modifier la BD (INSERT, UPDATE ou DELETE)

Enregistre dans la BD les modifications effectuées sur les entités d’un contexte de persistance

Automatiquement effectué à chaque commit

JPA

  • R. Grin

page 42

Données de la BD sont copiées dans l’entité Pour avoir la dernière version de l’entité

refresh(entité)

JPA

page 43

  • R. Grin

Un CP est un cache pour les accès à la BD Un find ou un 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 alors être la solution

Contexte de persistance - cache

JPA

  • R. Grin

page 44

Entité détachée

Une entité gérée par un EM peut être détachée de son contexte de persistance (par exemple si le EM est fermé ou l’entité envoyée « au loin »)

Pour que ces modifications soient enregistrées dans la BD, il est nécessaire de rattacher l’entité à un EM par la méthode merge (et de lancer ensuite un commit)

Cette entité détachée peut être modifiée

merge(a) Attention, merge(a) n’attache pas a Retourne une entité gérée qui a la même identité dans
merge(a)
Attention, merge(a) n’attache pas a
Retourne une entité gérée qui a la même
identité dans la BD que a, mais ça n’est pas le
même objet (sauf si l’objet était déjà géré)
Après un merge, l’application doit donc ne plus
utiliser cet objet ; il faut écrire ce type de code :
a = em.merge(a);
R. Grin
JPA
page 45
merge – une erreur à ne pas faire em.merge(dept); dept.addEmploye(emp); Quel est le problème ? L’ajout
merge – une erreur à ne pas faire
em.merge(dept);
dept.addEmploye(emp);
Quel est le
problème ?
L’ajout du nouvel employé ne sera pas
enregistré dans la base car l’objet référencé
par dept n’est pas géré ; le bon code :
dept = em.merge(dept);
dept.addEmploye(emp);
R. Grin
JPA
page 46
Identité des entités R. Grin JPA page 47
Identité des entités
R. Grin
JPA
page 47

JPA

  • R. Grin

page 48

Clé primaire

Une entité doit avoir un attribut, annoté @Id, qui correspond à la clé primaire dans la table associée

Ne jamais le modifier dès que l’entité représente des données de la base

Type primitif Java Classe qui enveloppe un type primitif java.lang.String java.util.Date java.sql.Date

Type de la clé primaire

JPA

page 49

  • R. Grin

JPA

  • R. Grin

page 50

Pour les clés de type nombre entier @GeneratedValue indique que la clé primaire sera générée par le SGBD Cette annotation peut avoir un attribut strategy qui indique comment la clé sera générée

Génération automatique de clé

Exemple @Id @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "EMP_SEQ") private long id; R. Grin JPA page
Exemple
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "EMP_SEQ")
private long id;
R. Grin
JPA
page 51

JPA

  • R. Grin

Peut arriver quand la BD existe déjà, en particulier quand la classe correspond à une table association (association M:N)

page 52

Pas recommandé, mais une clé primaire peut être composée de plusieurs colonnes

2 possibilités :

n @EmbeddedId et @Embeddable n @IdClass

Clé composite

Associations R. Grin JPA page 53
Associations
R. Grin
JPA
page 53

JPA

  • R. Grin

page 54

Association bidirectionnelle

Le développeur est responsable de la gestion correcte des 2 bouts de l’association

Méthode de gestion de l’association Pour faciliter la gestion des 2 bouts, il est commode d’ajouter
Méthode de gestion de l’association
Pour faciliter la gestion des 2 bouts, il est
commode d’ajouter une méthode qui effectue
tout le travail
Dans les associations 1-N, le bout « 1 » peut
comporter ce genre de méthode :
public void ajouterEmploye(Employe e) {
Departement d = e.getDept();
if (d != null)
d.employes.remove(e);
this.employes.add(e);
Dans quelle classe
est ce code ?
employe.setDept(this);
}
R. Grin
JPA
page 55

JPA

page 56

  • R. Grin

Un des 2 bouts est dit propriétaire de l’association ; celui qui correspond à la table qui contient la clé étrangère Pour les associations 1 – N, c’est le bout … ? N L’autre bout contient l’attribut mappedBy qui donne le nom de l’attribut dans le bout propriétaire

Bout propriétaire

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

JPA

  • R. Grin

page 59

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

Pourquoi « 1 ou 2 » ? On peut choisir le bout propriétaire

Association M:N

Exemple Dans quelle classe ? @ManyToMany private Collection<Projet> projets; @ManyToMany(mappedBy = "projets") private Collection<Employe> employes; Quel
Exemple
Dans quelle classe ?
@ManyToMany
private Collection<Projet> projets;
@ManyToMany(mappedBy = "projets")
private Collection<Employe> employes;
Quel est le bout propriétaire ?
Dans quelle table sera la clé étrangère ?
Dans quelle classe ?
R. Grin
JPA
page 60

JPA

  • R. Grin

page 61

Exemple :

Association entre les employés et les projets ; un employé a une fonction dans chaque projet auquel il participe

Association M:N avec information portée par l’association

JPA

  • R. Grin

page 62

Classe association

Association M:N traduite par une classe association Chaque classe qui participe à l’association peut avoir une collection d’objets de la classe association (suivant directionnalité) 2 possibilités pour la classe association :

n un attribut identificateur (@Id) unique (le plus simple) n un attribut identificateur par classe participant à l’association

@Entity public class Participation { @Id @GeneratedValue private int id; @ManyToOne private Employe employe; @ManyToOne private Projet projet; private String fonction;

JPA

page 63

  • R. Grin

Code classe association (début)

JPA

}

  • R. Grin

page 64

public Participation() { }

public Participation(Employe employe, Projet projet, String fonction) { this.employe = employe; this.projet = projet; this.fonction = fonction;

// Accesseurs pour employe et projet ...

Code classe association (fin)

JPA

  • R. Grin

page 65

Par défaut, JPA n’effectue pas automatiquement la persistance par transitivité : rendre persistant un département ne suffit pas à rendre persistants ses employés

Pas de persistance par transitivité automatique avec JPA

La cohérence des données de la BD repose donc sur le code de l’application

JPA

  • R. Grin

page 66

Soit une classe Departement qui contient une collection d’Employe Si un département est rendu persistant et si un des employés du département est non persistant, une IllegalStateException est lancée au moment du commit L’attribut cascade des associations peut simplifier le code

Cohérence des données

Cascade Les opérations persist, remove, refresh, merge peuvent être transmises par transitivité à l’autre bout d’une
Cascade
Les opérations persist, remove, refresh,
merge peuvent être transmises par
transitivité à l’autre bout d’une association
Exemple :
@OneToMany(
cascade = { CascadeType.PERSIST,
CascadeType.MERGE },
mappedBy = "client")
private Collection<Facture> factures;
Dans quelle classe est ce code ?
Qu’indique l’attribut cascade ?
R. Grin
JPA
page 67

JPA

page 68

  • R. Grin

Si elles sont récupérées, est-ce que les entités associées à ces entités doivent elles aussi être récupérées ?

Lorsqu’une entité est récupérée depuis la BD (Query ou find), est-ce que les entités

Le risque est de récupérer un très grand nombre d’entités inutiles

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

associées sont aussi récupérées ?

JPA

  • R. Grin

page 69

Mode EAGER : les données associées sont récupérées immédiatement Mode LAZY : les données associées ne sont récupérées que lorsque c’est vraiment nécessaire (lazy loading)

EAGER ou LAZY

JPA laisse le choix de récupérer ou non immédiatement les entités associées

Type de récupération par défaut des entités associées Mode EAGER pour les associations OneToOne et ManyToOne
Type de récupération par défaut
des entités associées
Mode EAGER pour les associations OneToOne
et ManyToOne
Mode LAZY pour les associations OneToMany
et ManyToMany
Vous voyez une raison pour ce choix ?
R. Grin
JPA
page 70
Indiquer le type de récupération des entités associées L’attribut fetch permet de modifier le comportement par
Indiquer le type de récupération
des entités associées
L’attribut fetch permet de modifier le
comportement par défaut
@OneToMany(mappedBy = "departement",
fetch = FetchType.EAGER)
private Collection<Employe> employes;
R. Grin
JPA
page 71
Héritage R. Grin JPA page 72
Héritage
R. Grin
JPA
page 72

JPA

  • R. Grin

page 73

La stratégie « une table distincte par classe concrète » est optionnelle (TABLE_PER_CLASS)

n une table par classe ; les tables sont jointes pour reconstituer les données (JOINED)

n une seule table pour une hiérarchie d’héritage (SINGLE_TABLE) ; par défaut

2 stratégies pour la traduction de l’héritage :

Stratégies

Toutes les classes traduites par une seule table Pour différencier les types de joueurs R. Grin
Toutes les classes traduites
par une seule table
Pour différencier
les types de joueurs
R. Grin
Mapping objet-relationnel
page 74
Exemple « 1 table par hiérarchie » @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) public abstract class Personne {
Exemple « 1 table par hiérarchie »
@Entity
@Inheritance(strategy =
InheritanceType.SINGLE_TABLE)
public abstract class Personne {
Dans la classe
racine de la
hiérarchie ;
optionnel
...
}
@Entity
« Employe » par défaut
@DiscriminatorValue("E")
public class Employe extends Personne {
...
}
R. Grin
JPA
page 75
Une table par classe Colonne discriminatrice R. Grin Mapping objet-relationnel page 76
Une table par classe
Colonne
discriminatrice
R. Grin
Mapping objet-relationnel
page 76
Préservation de l’identité Clé étrangère et primaire R. Grin Mapping objet-relationnel page 77
Préservation de l’identité
Clé étrangère et primaire
R. Grin
Mapping objet-relationnel
page 77
Exemple @Entity @Inheritance(strategy = InheritanceType.JOINED) public abstract class Personne { ... } @Entity @DiscriminatorValue("E") public class
Exemple
@Entity
@Inheritance(strategy =
InheritanceType.JOINED)
public abstract class Personne {
...
}
@Entity
@DiscriminatorValue("E")
public class Employe extends Personne {
...
}
R. Grin
JPA
page 78
Requêtes – JPQL Java Persistence Query Language R. Grin JPA page 79
Requêtes – JPQL
Java Persistence Query Language
R. Grin
JPA
page 79

JPA

  • R. Grin

page 80

IMPORTANT

Cette section concerne les entités retrouvées en interrogeant la base de données

Les modifications apportées à ces entités seront enregistrées au prochain commit

Toutes ces entités sont automatiquement gérées par le gestionnaire d’entités

Chercher par identité find retrouve une entité en donnant son identificateur dans la BD : Departement
Chercher par identité
find retrouve une entité en donnant son
identificateur dans la BD :
Departement dept =
em.find(Departement.class, 10);
R. Grin
JPA
page 81
Il est possible de rechercher des données sur des critères plus complexes que la simple
Il est possible de rechercher des données sur
des critères plus complexes que la simple
identité
R. Grin
JPA
page 82
Étapes pour récupérer des données 1. Décrire ce qui est recherché (langage JPQL) 2. Créer une
Étapes pour récupérer des données
1.
Décrire ce qui est recherché (langage JPQL)
2.
Créer une instance de type Query
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();
R. Grin
JPA
page 83
Exemple plus complexe String q = "select e from Employe as e " + "where e.departement.numero
Exemple plus complexe
String q = "select e from Employe as e "
+ "where e.departement.numero = :numero";
Query query = em.createQuery(q);
query.setParameter("numero", 10);
query.setMaxResults(30);
for (int i = 0; i < 5; i++) {
query.setFirstResult(30 * i);
List<Employe> listeEmployes =
(List<Employe>)query.getResultList();
...
// Affichage page numéro i + 1
}
R. Grin
JPA
page 84

Langage JPQL

  • R. Grin

page 85

JPA

Java Persistence Query Language décrit ce qui est recherché en utilisant le modèle objet (pas le modèle relationnel)

Les seules classes qui peuvent être utilisées sont les entités et les Embeddable

Exemples de requêtes Alias de classe obligatoire select e from Employe e select e.nom, e.salaire from
Exemples de requêtes
Alias de classe obligatoire
select e from Employe e
select e.nom, e.salaire from Employe e
select e from Employe e
where e.departement.nom = 'Direction'
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 86

JPA

  • R. Grin

page 87

List getResultList()

Object getSingleResult()

Obtenir le résultat de la requête

Résultat = plusieurs valeurs ou entités :

Résultat = une seule valeur ou entité :

JPA

page 88

  • R. Grin

Le type d’un élément du résultat est n Object si la clause select ne comporte qu’une seule expression n Object[] sinon

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

Exemple texte = "select e.nom, e.salaire " + " from Employe as e"; query = em.createQuery(texte);
Exemple
texte = "select e.nom, e.salaire "
+ " from Employe as e";
query = em.createQuery(texte);
List<Object[]> liste =
(List<Object[]>)query.getResultList();
for (Object[] info : liste) {
System.out.println(info[0] + " gagne "
+ info[1]);
}
R. Grin
JPA
page 89

Requête native (ou SQL) particulière à un SGBD : requête SQL avec tables et colonnes (pas classes et attributs) ;

JPA

  • R. Grin

page 90

createNativeQuery

Requête nommée : texte statique donné dans une annotation d’une entité ; le nom est passé en paramètre de createNamedQuery

Requête dynamique : texte donné en paramètre de createQuery

Types de requête

Exemple de requête nommée @Entity @NamedQuery ( name = "employe.findNomsEmpsDept", query = "select e.nom from Employe
Exemple de requête nommée
@Entity
@NamedQuery (
name = "employe.findNomsEmpsDept",
query = "select e.nom from Employe as e
where upper(e.departement.nom) = :nomDept"
)
public class Employe extends Personne {
...
Query q = em.createNamedQuery(
"employe.findNomsEmpsDept");
R.
Grin
JPA
page 91
Clauses d’un select
select
from
where
group by
having
order by
R.
Grin
JPA
page 93
Clauses where et having
Peuvent comporter :
n [NOT] LIKE, [NOT] BETWEEN, [NOT] IN
n AND, OR, NOT
n [NOT] EXISTS
n ALL, SOME/ANY
n IS [NOT] EMPTY, [NOT] MEMBER OF
Pour les collections
R.
Grin
JPA
page 95

Exemples de paramètres

page 92

  • R. Grin

JPA

Query query = em.createQuery( "select e from Employe as e " + "where e.nom = :nom"); query.setParameter("nom", "Dupond");

Query query = em.createQuery( "select e from Employe as e " + "where e.nom = ?1"); query.setParameter(1, "Dupond");

Polymorphisme dans les requêtes Les requêtes sont polymorphes : un nom de classe dans la clause
Polymorphisme dans les requêtes
Les requêtes sont polymorphes : un nom de
classe dans la clause from désigne cette
classe et toutes les sous-classes
Exemple :
select count(a) from Article as a
On peut restreindre à un type donné :
select a from Article a
where type(a) in (Stylo, Table)
R. Grin
JPA
page 94
Sous-requête where et having peuvent contenir des sous- requêtes (et peuvent être synchronisées) {ALL | ANY
Sous-requête
where et having peuvent contenir des sous-
requêtes (et peuvent être synchronisées)
{ALL | ANY | SOME} (sous-requête)
fonctionne comme dans SQL
Exemple :
select e from Employe e
where e.salaire >= ALL (
select e2.salaire from Employe e2
where e2.departement =
e.departement)
R. Grin
JPA
page 96
 

Navigation

Il est possible de suivre le chemin correspondant à une association avec la notation « pointée »

 
  • R. Grin

JPA

page 97

 
 

Règles pour les expressions de chemin

Une navigation peut être chaînée à une navigation précédente si la navigation précédente ne donne qu’une seule entité (OneToOne ou ManyToOne)

  • R. Grin

JPA

page 99

Exemple e alias pour Employe, n « e.departement » désigne le département d’un employé n «
Exemple
e alias pour Employe,
n « e.departement » désigne le
département d’un employé
n « e.projets » désigne les projets
auxquels participe un employé
select e.nom
from Employe as e
where e.departement.nom = 'Qualité'
R. Grin
JPA
page 98
Exemple select e.nom, e.departement.nom, e.superieur.departement.nom from Employe e R. Grin JPA page 100
Exemple
select e.nom,
e.departement.nom,
e.superieur.departement.nom
from Employe e
R. Grin
JPA
page 100
Contre-exemple « d.employes.nom » est interdit car d.employes est une collection Pour avoir les noms des
Contre-exemple
« d.employes.nom » est interdit car
d.employes est une collection
Pour avoir les noms des employés d’un
département, il faut une jointure :
select e.nom
from Departement d
join d.employes e
where d.nom = 'Direction'
R. Grin
JPA
page 101
Jointure Interne (jointure standard join) Externe (left outer join) Avec récupération de données en mémoire (join
Jointure
Interne (jointure standard join)
Externe (left outer join)
Avec récupération de données en mémoire
(join fetch) ; pour éviter le problème des
« N +1 selects »
R. Grin
JPA
page 102

select e.nom, particips.projet.nom from Employe e join e.participations particips

JPA

  • R. Grin

Exemples

page 103

select e.nom, d.nom from Employe e, Departement d where d = e.departement

join fetch Évite le problème des « N + 1 selects » select e from Employe
join fetch
Évite le problème des « N + 1 selects »
select e
from Employe as e
join fetch e.participations
Les participations placées à droite de join fetch
sont créées en même temps que les employés (mais
pas renvoyées par le select)
L’instruction
employe.getParticipations()
ne nécessitera pas d’accès à la base
R. Grin
JPA
page 104

Fonctions

Pour les chaînes de caractères : concat, substring, trim, lower, upper, length, locate

Arithmétique : abs, sqrt, mod, size Temporelles : current_date, current_time, current_timestamp

Fonctions de regroupement : count, max, min, avg

case (semblable CASE de SQL)

Grin

  • R. JPA

page 105

 

Opération de modification en volume

Grin

  • R. JPA

page 107

JPA

  • R. Grin

page 106

API « criteria »

Introduite par JPA 2.0

Les requêtes JPQL sont des String qui peuvent contenir des erreurs (par exemple le nom d’une classe qui n’existe pas)

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

Tout ce qui peut être fait avec JPQL peut l’être avec cette API

JPA

  • R. Grin

page 108

Utilité

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

Augmenter les 10000 employés de 5% Mauvaise solution :

n Modifier le salaire de chaque entité n Enregistrer ces modifications dans la base

n Créer toutes les entités « Employe » en lisant les données dans la base

Exemple em.getTransaction().begin(); String ordre = "update Employe e " + " set e.salaire = e.salaire *
Exemple
em.getTransaction().begin();
String ordre =
"update Employe e " +
" set e.salaire = e.salaire * 1.05";
Query q = em.createQuery(ordre);
int nbEntitesModif = q.executeUpdate();
em.getTransaction().commit();
R. Grin
JPA
page 109
Exceptions R. Grin JPA page 110
Exceptions
R. Grin
JPA
page 110
 

Exceptions de JPA

JPA n’utilise que des exceptions non contrôlées Elles héritent de PersistenceException

  • R. Grin

JPA

page 111

 
 

Transaction

  • R. Grin

JPA

page 113

EntityNotFoundException EntityExistsException TransactionRequiredException RollbackException OptimisticLockException PessimisticLockException * LockTimeoutException * NonUniqueResultException * NoResultException * : ne marquent pas la transaction pour un rollback

Types d’exception

JPA

  • R. Grin

page 112

Les entités Java gardent les valeurs qu’elles avaient au moment du rollback, mais ces valeurs sont le plus souvent fausses

Le plus souvent il faut donc relancer des requêtes pour récupérer des entités avec des valeurs correctes

n le contexte de persistance est vidé ; toutes les entités deviennent détachées

En cas de rollback, n rollback dans la base de données

JPA

  • R. Grin

page 114

Rollback

Concurrence R. Grin JPA page 115
Concurrence
R. Grin
JPA
page 115

Si une autre transaction a modifié entre- temps les données de la BD correspondant à l’entité, il y aura un problème de mise à jour perdue

JPA

  • R. Grin

page 116

L’entité est ensuite modifiée par l’application puis la transaction est validée

Exemple de problème de concurrence « BD »

Une entité est récupérée depuis la BD (par un find par exemple)

JPA

  • R. Grin

page 117

Gestion de la concurrence

n on pense qu’aucune autre transaction ne modifiera les données sur lesquelles on va travailler n donc aucune blocage n’est effectué dans la base de données n au moment du commit, vérifications pour voir si on avait raison d’être optimiste n si on avait tort, rollback de la transaction

Par défaut, les problèmes d’accès concurrents sont gérés avec une stratégie optimiste :

@Version Pour savoir si l’état d’une entité a été modifié entre 2 moments différents, on utilise
@Version
Pour savoir si l’état d’une entité a été modifié
entre 2 moments différents, on utilise un
numéro de version enregistré dans la base
Ce numéro est incrémenté automatiquement
par JPA à chaque modification
Ne doit jamais être modifié par l’application
Exemple :
@Version
private int version;
R. Grin
JPA
page 118

JPA

  • R. Grin

page 119

lock(A, mode)

Permet en particulier d’effectuer un blocage pessimiste (blocage dans la base) Les méthodes find et refresh de EntityManager ont une variante qui permet de bloquer les entités retrouvées ou rafraichies

Protège une entité contre les accès concurrents pour les cas où la protection offerte par défaut ne suffit pas

JPA

  • R. Grin

page 120

Quand elle est rattachée à un EM, le 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

Une entité est détachée de son EM Elle est modifiée

Concurrence et entité détachée