La lecture en ligne est gratuite
Le téléchargement nécessite un accès à la bibliothèque YouScribe
Tout savoir sur nos offres
Télécharger Lire

Java Persistence API

De
49 pages
  • mémoire
1JPA 2.0 (Java Persistence API) - Partie 2 Université de Nice - Sophia Antipolis Version 2.15 – 1/2/12 Richard Grin R. Grin JPA page 2 Plan de la partie 2 (1/2) ‰ Récupérer des données de la base ‰ Langage d'interrogation JPQL ‰ API « Critère » ‰Modifications en volume ‰ Exceptions ‰ Transaction ‰ Concurrence ‰ Entités détachées ‰ Configuration d'une unité de persistance R.
  • méthodes setparameter
  • string nom
  • query
  • count
  • select matr
  • clause select
  • exemples ‰
  • requêtes
  • requête
  • données
  • donnée
  • noms
  • nom
Voir plus Voir moins





















Plan de la partie 2 (1/2)
Récupérer des données de la baseJPA 2.0
Langage d’interrogation JPQL
(Java Persistence API) API « Critère »
Modifications en volume-Partie 2
Exceptions
TransactionUniversité de Nice - Sophia Antipolis
ConcurrenceVersion 2.15 – 1/2/12
Richard Grin Entités détachées
Configuration d’une unité de persistance
R. Grin JPA page 2
Plan de la partie 2 (2/2)
Fichiers de configuration XML
JPA et DAOs
Cache des données Récupérer des données
Optimisation de la base de données
Méthodes callbacks et écouteurs
Validation
Adaptation à une base de données préexistante
Précisions pour la génération du schéma de la
base de données
R. Grin JPA page 3 R. Grin JPA page 4
Rappel important
Toutes les entités retrouvées par find,
Cette section montre comment interroger la getReference ou un query sont
base de données pour récupérer des entités automatiquement gérées par le gestionnaire
(des employés par exemple) ou des simples d’entités
valeurs (des noms d’employés ou le total des
Les modifications apportées à ces entités sont
salaires des employés par exemple)
donc enregistrées au prochain commit (mais
les nouveaux objets associés à l’entité
retrouvée ne sont pas automatiquement
persistants même s'il y a une cascade sur
persist ; ça ne marche que pour un appel
explicite de la méthode persist)
R. Grin JPA page 5 R. Grin JPA page 6
1‰









ExempleChercher par identité
find et getReference (de EntityManager) Departement dept =
em.find(Departement.class, 10);permettent de retrouver une entité en donnant
son identificateur dans la BD
<T> T find(Class<T> classeEntité,
Object cléPrimaire)
<T> T
getReference(Class<T> classeEntité,
Object cléPrimaire)
Le résultat est null si aucune entité n’a cet
identificateur dans la base de donnée
R. Grin JPA page 7 R. Grin JPA page 8
getReference getReference
getReference renvoie une référence vers une getReference peut être (rarement) utilisée
entité, sans que cette entité ne soit pour améliorer les performances quand une
nécessairement initialisée entité non initialisée peut être suffisante, sans
que l’entité entière soit retrouvée dans la base Le plus souvent il vaut mieux utiliser find
de données
Par exemple, pour indiquer une association dont
le but est unique (OneToOne ou ManyToOne) :
Departement dept =
em.getReference(Departement.class, 10);
Employe emp.setDepartement(dept);
R. Grin JPA page 9 R. Grin JPA page 10
Interroger la base de données É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 ou criteria API)
identité 2. Créer une instance de type Query
Remarque : dans toute la partie à venir sur 3. Initialiser la requête (paramètres, pagination)
les requêtes (query, JPQL, API criteria),
4. Lancer l’exécution de la requête
« entité » peut désigner une entité ou une
classe (ou instance de) Embeddable ; depuis
JPA 2.0, les classes Embeddable ont les
« mêmes droits » que les classes entités
R. Grin JPA page 11 R. Grin JPA page 12
2‰










Exemple plus complexeExemple
String q = "select e from Employe as e "
String s = "select e from Employe as e";
+ "where e.departement.numero = :numero";
Query query = em.createQuery(s);
Query query = em.createQuery(q);
List<Employe> listeEmployes =
query.setParameter("numero", 10);(List<Employe>)query.getResultList();
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 13 R. Grin JPA page 14
Description de la requête Requêtes sur les entités « objet »
Les requêtes JPQL ou « criteria » travaillent avec Le langage JPQL (Java Persistence Query
le modèle objet et pas avec le modèle relationnelLanguage) permet de décrire ce que
l’application recherche (voir prochaine section) Les identificateurs désignent les entités et leurs
attributs et pas les tables et leurs colonnesIl ressemble beaucoup à SQL :
select e from Employe e Les seules classes qui peuvent être explicitement
where e.nom = 'Dupond' désignées (par leur nom) dans une requête sont
L’API « Criteria » a été introduite par JPA 2.0 les entités et les classes « Embeddable »
pour décrire la requête d’une façon plus sûre, Rappel : le nom est donné par l’attribut @name de
vérifiée à la compilation (étudiée à la suite de @Entity ou @Embeddable, ou, par défaut, par
JPQL) le nom de la classe
R. Grin JPA page 15 R. Grin JPA page 16
QueryType du résultat
L’expression renvoyée peut être Pour faire exécuter la requête il faut créer un
Query, instance qui représente une requête n une (ou plusieurs) expression « entité »,
par exemple un employé (e par exemple) (étudiée en détails un peu plus loin)
Plusieurs méthodes de EntityManagern une « valeur »,
permettent d’obtenir un Query, suivant la par exemple le nom d’un employé (e.nom),
façon dont la requête a été décritey compris une expression arithmétique
(e.salaire * 1.25)
L’expression ne peut pas être une collection
(d.employes par exemple), bien que certains
fournisseurs de persistance le permettent !
R. Grin JPA page 17 R. Grin JPA page 18
3‰











Méthodes pour obtenir un Query Exécuter une requête (1)
Les méthodes suivantes de EntityManager Plusieurs méthodes de l’interface Query
renvoient un Query ; elles sont liées au permettent d’exécuter une requête et de
langage JPQL, à l’API « criteria », aux requêtes récupérer son résultat
natives SQL et aux requêtes nommées (tout
cela sera étudié dans la suite du cours)
createQuery(String jpql)(CriteriaQuery criteria)
createNativeQuery(String sql)
createNamedQuery(String nom)
R. Grin JPA page 19 R. Grin JPA page 20
Exécuter une requête (2) Exécuter une requête (3)
Si plusieurs valeurs ou entités peuvent être Pour le cas où une seule valeur ou entité est
renvoyées, il faut utiliser la méthode renvoyée, le plus simple est d’utiliser la
getResultList() de l’interface Queryméthode getSingleResult() ; elle renvoie
un Object Elle renvoie une liste « raw » (pas générique)
des résultats, instance de java.util.List, La méthode lance des exceptions s’il n’y a
éventuellement vide si le résultat est videpas exactement une entité qui correspond à
la requête : Un message d’avertissement est affiché
durant la compilation si le résultat est rangé nNoResultException
dans une liste générique (List<Employe>
nNonUniqueResultException
par exemple)
R. Grin JPA page 21 R. Grin JPA page 22
Type d’un élément Exemple 1 : renvoie une entité
du résultat
String s = "select e from Employe as e";
Query query = em.createQuery(s);
Le type d’un élément de la liste (ou de
List<Employe> listeEmployes = l’unique valeur ou entité renvoyée) est
(List<Employe>)query.getResultList();
nObject si la clause select ne comporte
qu’une seule expression
nObject[] si elle comporte plusieurs On peut faire un cast
expressions
R. Grin JPA page 23 R. Grin JPA page 24
4‰












Exemple 2 : renvoie une propriété Exemple 3 : renvoie plusieurs valeurs
String s = texte = "select e.nom, e.salaire "
"select e.nom from Employe as e"; + " from Employe as e";
Query query = em.createQuery(s); query = em.createQuery(texte);
List<String> listeEmployes = List<Object[]> liste =
(List<String>)query.getResultList(); (List<Object[]>)query.getResultList();
for (Object[] info : liste) {
System.out.println(info[0] + " gagne "
On peut faire un cast + info[1]);
}
R. Grin JPA page 25 R. Grin JPA page 26
Méthodes de Query (1) Méthodes de Query (2)
List getResultList() Query setParameter(String nom,
Object valeur)Object getSingleResult()int executeUpdate()
Date valeur, TemporalType Query setMaxResults(int
typeTemporel)nbResultats)
Query setParameter(String nom,
Query setFirstResult(int
Calendar valeur, TemporalType positionDepart)
typeTemporel)
Query setFlushMode(FlushModeType
modeFlush)
R. Grin JPA page 27 R. Grin JPA page 28
Types temporels Exemple
@Temporal(TemporalType.DATE)On a vu que les 2 types java temporels du
private Calendar dateEmb;paquetage java.util (Date et Calendar)
em.createQuery("select e from employe e"nécessitent une annotation @Temporal
+ " where e.dateEmb between ?1 and ?2")
Ils nécessitent aussi un paramètre .setParameter(1, debut, TemporalType.DATE)
supplémentaire pour la méthode arameter(2, fin, TemporalType.DATE)
setParameter .getResultList();
R. Grin JPA page 29 R. Grin JPA page 30
5‰















Types de requête Paramètres des requêtes
Requête dynamique dont le texte JPQL est
Un paramètre peut être désigné par son donné en paramètre de createQuery
numéro (?n) ou par son nom (:nom)
Requête native (ou requête SQL) particulière à
Les valeurs des paramètres sont données
un SGBD ou trop complexe pour JPA ; requête
par les méthodes setParameter
SQL (pas JPQL) avec tables et colonnes (pas
Les paramètres sont numérotés à partir de 1classes et attributs) ; createNativeQuery
Un paramètre peut être utilisé plus d’une fois Requête nommée dont le texte est donné
dans une requêtestatiquement dans une annotation d’une entité
et dont le nom est passé en paramètre de L’usage des paramètres nommés est
createNamedQuery ; une requête nommée recommandé (plus lisible)
peut être écrite en JPQL ou en SQL (native)
R. Grin JPA page 31 R. Grin JPA page 32
Requête nommée (1) Requête nommée (2)
Seules les entités peuvent contenir des Les requêtes nommées peuvent être
définitions de requêtes nommées analysée et précompilées par le fournisseur
de persistance au démarrage de l’application, Une requête nommée peut être mise dans
ce qui peut améliorer les performancesn’importe quelle entité, mais on choisira le
plus souvent l’entité qui correspond à ce qui L’annotation @NamedQuery définit une
est renvoyé par la requête requête nommée écrite en JPQL@NamedNativeQuery définit Le nom de la requête nommée doit être
unique parmi toutes les entités de l’unité de une requête nommée écrite en SQL (native)
persistance ; on pourra, par exemple, préfixer
le nom par le nom de l’entité : Employe.findAll
R. Grin JPA page 33 R. Grin JPA page 34
Exemple de requête nommée Exemples
@Entity
Query query = em.createQuery(
@NamedQuery ( "select e from Employe as e "
name="findNomsEmployes", + "where e.nom = ?1");
query.setParameter(1, "Dupond");query="select e.nom from Employe as e
where upper(e.departement.nom) = :nomDept" Query query = em.createQuery(
"select e from Employe as e ")
+ "where e.nom = :nom");public class Employe extends Personne {
query.setParameter("nom", "Dupond");
...
Query q =
em.createNamedQuery("findNomsEmployes");
R. Grin JPA page 35 R. Grin JPA page 36
6‰











Plusieurs requêtes nommées Mapping pour requêtes natives (1)
Si une classe a plusieurs requêtes nommées, Il est nécessaire de donner des informations
il faut les regrouper dans une annotation sur les colonnes renvoyées par la requête
@NamedQueries : SQL afin que le gestionnaire d’entités sache
@NamedQueries({ si elle correspondent à des entités
@NamedQuery(...),
Dans le cas où toutes les colonnes @NamedQuery,
correspondent aux attributs d’une entité ces ...
informations de mapping sont indiquées en })
donnant la classe de l’entité en paramètre de
createNativeQuery
R. Grin JPA page 37 R. Grin JPA page 38
Exemple Mapping pour requêtes natives (2)
String requete = Dans les autres cas, une annotation
"select matr, nome,…, dept " @SqlResultSetMapping est nécessaire
SQL Oracle+ " from emp " Elle doit être ajoutée à une entité quelconque(connect by)
+ " start with matr = ?1 "
Cette annotation a un nom qui doit être passé
+ " connect by prior matr = sup ";
en paramètre à la méthode
List<Employe> employes = (List<Employe>) createNativeQuery
em.createNativeQuery(requete,
Consultez une documentation sur JPA pour
Employe.class)
en savoir plus
.setParameter(1, idChef);
.getResultList();
R. Grin JPA page 39 R. Grin JPA page 40
Mode de flushRequêtes natives ou JDBC ?
Normalement (mode FlushMode.AUTO) un
Si une entité est renvoyée par la requête, il flush des entités concernées par une requête
vaut mieux utiliser une requête native car le est effectué avant la requête pour que le
gestionnaire d’entités gérera l’entité comme résultat tienne compte des modifications
les autres entités et le code est plus simple effectuées en mémoire sur ces entités
Si des valeurs scalaires sont renvoyées, le Pour une requête il est possible d'éviter ce
choix est moins clair ; utiliser une requête flush avec la méthode setFlushMode :
nommée permettra de rester dans JPA query.setFlushMode(FlushMode.COMMIT);
Dans ce mode, seul un commit provoquera un Rarement, une requête trop complexe
flushimposera JDBC
R. Grin JPA page 41 R. Grin JPA page 42
7‰

















Pagination du résultat Enchaînement des méthodes
Query setMaxResults(int n) : indique Les méthodes setParameter,
setMaxResults renvoient le Query modifiéle nombre maximum de résultats à retrouver
Query setFirstResult(int n) : indique On peut donc les enchaîner
erla position du 1 résultat à retrouver Exemple :
(numéroté à partir de 0) em.createQuery(texteQuery)
.setParameter(nomParam, valeurParam)
.setFirstResult(30 * i)
.setMaxResults(30)
.getResultList();
R. Grin JPA page 43 R. Grin JPA page 44
Exemples de requêtes JPQL
select e from Employe as et e.nom, e.salaire from Employe e
select e from Employe e
where e.departement.nom = 'Direction'Langage JPQL –
select d.nom, avg(e.salaire) Java Persistence Query Language from Departement d join d.employes e
group by d.nom
having count(d.nom) > 5
R. Grin JPA page 45 R. Grin JPA page 46
Alias Clauses d’un select
Le texte des requêtes utilise les alias de select : type des objets ou valeurs
classe : « select e from Employe as e » renvoyées
from : où les données sont récupéréesLes attributs des classes doivent être préfixés
par les alias : « e.nom » where : sélectionne les données
Une erreur fréquente du débutant est groupby : regroupe des données
d’oublier les alias en préfixe having : sélectionne les groupes (ne peut
exister sans clause group by)
orderby : ordonne les données
R. Grin JPA page 47 R. Grin JPA page 48
8‰











Polymorphisme dans les requêtes (1)
Les mots-clés select, from, distinct, Toutes les requêtes sont polymorphes : un
join,… sont insensibles à la casse nom de classe dans la clause from désigne
cette classe et toutes les sous-classes
Exemple :
select count(a) from Article as a
compte le nombre d’instances de la classe
Article et de tous les sous-classes de
Depuis JPA 2 on peut restreindre à un type
donné : select a from Article where type(a)
R. Grin JPA page 49 R. Grin JPA page 50
Polymorphisme dans les requêtes (2) Expression de chemin
Depuis JPA 2 on peut restreindre à un type Les requêtes peuvent contenir des
donné : expressions de chemin pour naviguer entre
select a from Article a les entités en suivant les associations
where type(a) in (Stylo, Lot) déclarées dans le modèle objet (les
annotations @OneToOne, @OneToMany, …)
La notation « pointée » est utilisée
R. Grin JPA page 51 R. Grin JPA page 52
ExemplesRègle pour les
Si e est un alias pour Employe, expressions de chemin
n «e.departement » désigne le
département d’un employéUne navigation peut être chaînée à une
n «e.projets » désigne la collection de navigation précédente à la condition que la
projets auxquels participe un employénavigation précédente ne donne qu’une seule
select e.nomentité (OneToOne ou ManyToOne)
from Employe as e
Dans le cas où une navigation aboutit à
where e.departement.nom = 'Qualité'
plusieurs entités, il est possible d’utiliser la
e.projets.nom n’est pas autorisé car clause join étudiée plus loin pour obtenir
e.projets est une collection (voir clause ces entités
join)
R. Grin JPA page 53 R. Grin JPA page 54
9‰







distinctAutre exemple
select e.nom, Dans une clause select, indique que les
e.departement.nom, valeurs dupliquées sont éliminées (la requête
e.superieur.departement.nom ne garde qu’une seule des valeurs égales)
from Employe e Exemple :
select distinct e.departement
from Employe e
R. Grin JPA page 55 R. Grin JPA page 56
new Group by
On peut regrouper sur un alias ou sur attribut ; Il est possible de renvoyer des instances d’une
on regroupe ici sur un alias :classe dont le constructeur prend en paramètre
select d, count(e)
des informations récupérées dans la base de
from Departement d
données
join d.employes e
La classe doit être désignée par son nom group by d
complet (avec le nom du paquetage)
Les expressions du select (ou du order by s’il
Exemple : y en a un) qui ne sont pas des regroupements
select new p1.p2.Classe(e.nom, e.salaire)
doivent se trouver aussi dans le group by, ce from Employe e
qui peut amener à ajouter une expression
« inutile » dans le group by
R. Grin JPA page 57 R. Grin JPA page 58
Clauses where et having Exemple
select d.nom, avg(e.salaire)Ces clauses peuvent comporter les mots-clés
from Departement d join d.employes esuivants :
group by d.nom
n[NOT]LIKE, [NOT]BETWEEN, [NOT]IN
having count(d.nom) > 3
nAND, OR, NOT
n[NOT]EXISTS
nALL, SOME/ANY
nIS [NOT] NULL
nIS[NOT]EMPTY, [NOT]MEMBEROF (pour
les collections)
R. Grin JPA page 59 R. Grin JPA page 60
10