(Java Persistence API) Langage d’interrogation...

49
1 JPA 2.0 (Java Persistence API) Java SE - Partie 2 Université de Nice - Sophia Antipolis Version 2.17.3 – 2/1/13 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é détachée Configuration d’une unité de persistance R. Grin JPA page 3 Plan de la partie 2 (2/2) Fichiers de configuration XML JPA et DAOs Cache des données Optimisation 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 4 Récupérer des données de la base de données R. Grin JPA page 5 Cette section montre comment interroger la base de données pour récupérer des entités (des employés par exemple) ou des simples valeurs (des noms d’employés ou le total des salaires des employés par exemple) R. Grin JPA page 6 Rappel important Toutes les entités retrouvées par find, getReference ou un query sont automatiquement gérées par le gestionnaire d’entités Les modifications apportées à ces entités sont 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)

Transcript of (Java Persistence API) Langage d’interrogation...

Page 1: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

1

JPA 2.0(Java Persistence API)

Java SE- Partie 2

Université de Nice - Sophia AntipolisVersion 2.17.3 – 2/1/13

Richard Grin

R. Grin JPA page 2

Plan de la partie 2 (1/2)

Récupérer des données de la baseLangage d’interrogation JPQLAPI « Critère »Modifications en volumeExceptionsTransactionConcurrenceEntité détachéeConfiguration d’une unité de persistance

R. Grin JPA page 3

Plan de la partie 2 (2/2)

Fichiers de configuration XMLJPA et DAOsCache des donnéesOptimisationMéthodes callbacks et écouteursValidationAdaptation à une base de données préexistantePrécisions pour la génération du schéma de la base de données

R. Grin JPA page 4

Récupérer des données de la base de données

R. Grin JPA page 5

Cette section montre comment interroger la base de données pour récupérer des entités (des employés par exemple) ou des simples valeurs (des noms d’employés ou le total des salaires des employés par exemple)

R. Grin JPA page 6

Rappel importantToutes les entités retrouvées par find, getReference ou un query sont automatiquement gérées par le gestionnaire d’entitésLes modifications apportées à ces entités sont 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)

Page 2: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

2

R. Grin JPA page 7

Chercher par identité

find et getReference (de EntityManager) 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 8

Exemple

Departement dept =em.find(Departement.class, 10);

R. Grin JPA page 9

getReference

getReference renvoie une référence vers une entité, sans que cette entité ne soit nécessairement initialiséeLe plus souvent il vaut mieux utiliser find

R. Grin JPA page 10

getReference

getReference peut être (rarement) utilisée pour améliorer les performances quand une entité non initialisée peut être suffisante, sans que l’entité entière soit retrouvée dans la base de donnéesPar 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 11

Interroger la base de donnéesIl est possible de rechercher des données sur des critères plus complexes que la simple identitéRemarque : dans toute la partie à venir sur les requêtes (query, JPQL, API criteria), « 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 12

Étapes pour récupérer des données1. Décrire ce qui est recherché (langage JPQL

ou criteria API)2. Créer une instance de type Query3. Initialiser la requête (paramètres, pagination)4. Lancer l’exécution de la requête

Page 3: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

3

R. Grin JPA page 13

Exemple

String s = "select e from Employe as e"; Query query = em.createQuery(s); List<Employe> listeEmployes = (List<Employe>)query.getResultList();

R. Grin JPA page 14

Exemple plus complexeString 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 15

Description de la requête

Le langage JPQL (Java Persistence QueryLanguage) permet de décrire ce que l’application recherche (voir prochaine section)Il ressemble beaucoup à SQL :select e from Employe e where e.nom = 'Dupond'

L’API « Criteria » a été introduite par JPA 2.0 pour décrire la requête d’une façon plus sûre, vérifiée à la compilation (étudiée à la suite de JPQL)

R. Grin JPA page 16

Requêtes sur les entités « objet »

Les requêtes JPQL ou « criteria » travaillent avec le modèle objet et pas avec le modèle relationnelLes identificateurs désignent les entités et leurs attributs et pas les tables et leurs colonnesLes seules classes qui peuvent être explicitement désignées (par leur nom) dans une requête sont les entités et les classes « Embeddable »Rappel : le nom est donné par l’attribut @name de @Entity ou @Embeddable, ou, par défaut, par le nom de la classe

R. Grin JPA page 17

Type du résultat

L’expression renvoyée peut être n une (ou plusieurs) expression « entité »,

par exemple un employé (e par exemple)n une (ou plusieurs) expression « valeur »,

par exemple le nom d’un employé (e.nom), y 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 !

Query

Pour faire exécuter la requête il faut créer un Query, instance qui représente une requête (étudiée en détails un peu plus loin)Plusieurs méthodes de EntityManagerpermettent d’obtenir un Query, suivant la façon dont la requête a été décrite

R. Grin JPA page 18

Page 4: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

4

Méthodes pour obtenir un Query

Les méthodes suivantes de EntityManagerrenvoient un Query ; elles sont liées au langage JPQL, à l’API « criteria », aux requêtes natives SQL et aux requêtes nommées (tout cela sera étudié dans la suite du cours)createQuery(String jpql)createQuery(CriteriaQuery criteria)createNativeQuery(String sql)createNamedQuery(String nom)

R. Grin JPA page 19

Exécuter une requête (1)

Plusieurs méthodes de l’interface Querypermettent d’exécuter une requête et de récupérer son résultat

R. Grin JPA page 20

R. Grin JPA page 21

Exécuter une requête (2)

Pour le cas où une seule valeur ou entité est renvoyée, le plus simple est d’utiliser la méthode getSingleResult() ; elle renvoie un ObjectLa méthode lance des exceptions s’il n’y a pas exactement une entité qui correspond à la requête :n NoResultExceptionn NonUniqueResultException

R. Grin JPA page 22

Exécuter une requête (3)

Si plusieurs valeurs ou entités peuvent être renvoyées, il faut utiliser la méthode getResultList() de l’interface QueryElle renvoie une liste « raw » (pas générique) des résultats, instance de java.util.List, éventuellement vide si le résultat est videUn message d’avertissement est affiché durant la compilation si le résultat est rangé dans une liste générique (List<Employe>par exemple)

R. Grin JPA page 23

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

Le type d’un élément de la liste (ou de l’unique valeur ou entité renvoyée) estn Object si la clause select ne comporte

qu’une seule expressionn Object[] si elle comporte plusieurs

expressions

R. Grin JPA page 24

Exemple 1 : renvoie une entité

String s = "select e from Employe as e"; Query query = em.createQuery(s); List<Employe> listeEmployes = (List<Employe>)query.getResultList();

On peut faire un cast

Page 5: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

5

R. Grin JPA page 25

Exemple 2 : renvoie une propriété

String s = "select e.nom from Employe as e";

Query query = em.createQuery(s); List<String> listeEmployes = (List<String>)query.getResultList();

On peut faire un cast

R. Grin JPA page 26

Exemple 3 : renvoie plusieurs valeurs

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 27

Méthodes de Query (1)

List getResultList()Object getSingleResult()int executeUpdate()Query setMaxResults(intnbResultats)Query setFirstResult(intpositionDepart)Query setFlushMode(FlushModeTypemodeFlush)

R. Grin JPA page 28

Méthodes de Query (2)

Query setParameter(String nom, Object valeur)Query setParameter(String nom, Date valeur, TemporalType typeTemporel)Query setParameter(String nom, Calendar valeur, TemporalType typeTemporel)

R. Grin JPA page 29

Types temporels

On a vu que les 2 types java temporels du paquetage java.util (Date et Calendar) nécessitent une annotation @TemporalIls nécessitent aussi un paramètre supplémentaire pour la méthode setParameter

R. Grin JPA page 30

Exemple

@Temporal(TemporalType.DATE)private Calendar dateEmb;em.createQuery("select e from employe e"+ " where e.dateEmb between ?1 and ?2").setParameter(1, debut, TemporalType.DATE).setParameter(2, fin, TemporalType.DATE).getResultList();

Page 6: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

6

R. Grin JPA page 31

Types de requêteRequête dynamique dont le texte JPQL est donné en paramètre de createQueryRequête native (ou requête SQL) particulière à un SGBD ou trop complexe pour JPA ; requête SQL (pas JPQL) avec tables et colonnes (pas classes et attributs) ; createNativeQueryRequête nommée dont le texte est donné statiquement dans une annotation d’une entité et dont le nom est passé en paramètre de createNamedQuery ; une requête nommée peut être écrite en JPQL ou en SQL (native)

R. Grin JPA page 32

Paramètres des requêtes

Un paramètre peut être désigné par son numéro (?n) ou par son nom (:nom)Les valeurs des paramètres sont données par les méthodes setParameterLes paramètres sont numérotés à partir de 1Un paramètre peut être utilisé plus d’une fois dans une requêteL’usage des paramètres nommés est recommandé (plus lisible)

R. Grin JPA page 33

Requête nommée (1)

Seules les entités peuvent contenir des définitions de requêtes nomméesUne requête nommée peut être mise dans n’importe quelle entité, mais on choisira le plus souvent l’entité qui correspond à ce qui est renvoyé par la requêteLe nom de la requête nommée doit être unique parmi toutes les entités de l’unité de persistance ; on pourra, par exemple, préfixer le nom par le nom de l’entité : Employe.findAll

R. Grin JPA page 34

Requête nommée (2)

Les requêtes nommées peuvent être analysée et précompilées par le fournisseur de persistance au démarrage de l’application, ce qui peut améliorer les performancesL’annotation @NamedQuery définit une requête nommée écrite en JPQLL’annotation @NamedNativeQuery définit une requête nommée écrite en SQL (native)

R. Grin JPA page 35

Exemple de requête nommée@Entity@NamedQuery (name="findNomsEmployes",query="select e.nom from Employe as e where upper(e.departement.nom) = :nomDept"

)public class Employe extends Personne {...

Query q = em.createNamedQuery("findNomsEmployes");

R. Grin JPA page 36

Exemples

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

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

query.setParameter("nom", "Dupond");

Page 7: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

7

R. Grin JPA page 37

Plusieurs requêtes nommées

Si une classe a plusieurs requêtes nommées, il faut les regrouper dans une annotation @NamedQueries :@NamedQueries({@NamedQuery(...),@NamedQuery(...),...

})

Mapping pour requêtes natives (1)

Il est nécessaire de donner des informations sur les colonnes renvoyées par la requête SQL afin que le gestionnaire d’entités sache si elle correspondent à des entitésDans le cas où toutes les colonnes 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 38

Exemple

String requete ="select matr, nome,…, dept "+ " from emp "+ " start with matr = ?1 "+ " connect by prior matr = sup ";

List<Employe> employes = (List<Employe>)em.createNativeQuery(requete,

Employe.class).setParameter(1, idChef);.getResultList();

R. Grin JPA page 39

SQL Oracle(connect by)

Mapping pour requêtes natives (2)

Dans les autres cas, une annotation @SqlResultSetMapping est nécessaireElle doit être ajoutée à une entité quelconqueCette annotation a un nom qui doit être passé en paramètre à la méthode createNativeQuery

Consultez une documentation sur JPA pour en savoir plus

R. Grin JPA page 40

Requêtes natives ou JDBC ?

Si une entité est renvoyée par la requête, il vaut mieux utiliser une requête native car le gestionnaire d’entités gérera l’entité comme les autres entités et le code est plus simpleSi des valeurs scalaires sont renvoyées, le choix est moins clair ; utiliser une requête nommée permettra de rester dans JPARarement, une requête trop complexe imposera JDBC

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

Mode de flushNormalement (mode FlushMode.AUTO) un flush des entités concernées par une requête est effectué avant la requête pour que le résultat tienne compte des modifications effectuées en mémoire sur ces entitésPour une requête il est possible d'éviter ce flush avec la méthode setFlushMode :query.setFlushMode(FlushMode.COMMIT);Dans ce mode, seul un commit provoquera un flush

Page 8: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

8

R. Grin JPA page 43

Pagination du résultat

Query setMaxResults(int n) : indique le nombre maximum de résultats à retrouverQuery setFirstResult(int n) : indique la position du 1er résultat à retrouver (numéroté à partir de 0)

R. Grin JPA page 44

Enchaînement des méthodes

Les méthodes setParameter, setMaxResults renvoient le Query modifiéOn peut donc les enchaînerExemple :em.createQuery(texteQuery).setParameter(nomParam, valeurParam).setFirstResult(30 * i).setMaxResults(30).getResultList();

R. Grin JPA page 45

Langage JPQL –Java Persistence Query Language

R. Grin JPA page 46

Exemples de requêtes JPQL

select e from Employe as eselect e.nom, e.salaire from Employe eselect 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.nomhaving count(d.nom) > 5

R. Grin JPA page 47

Alias

Le texte des requêtes utilise les alias de classe : « select e from Employe as e »Les attributs des classes doivent être préfixés par les alias : « e.nom »Une erreur fréquente du débutant est d’oublier les alias en préfixe

R. Grin JPA page 48

Clauses d’un select

select : type des objets ou valeurs renvoyéesfrom : où les données sont récupéréeswhere : sélectionne les donnéesgroup by : regroupe des donnéeshaving : sélectionne les groupes (ne peut exister sans clause group by)order by : ordonne les données

Page 9: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

9

R. Grin JPA page 49

Les mots-clés select, from, distinct, join,… sont insensibles à la casse

R. Grin JPA page 50

Polymorphisme dans les requêtes (1)

Toutes les requêtes sont polymorphes : un nom de classe dans la clause from désigne cette classe et toutes les sous-classesExemple :select count(a) from Article as acompte le nombre d’instances de la classe Article et de tous les sous-classes de Article

Depuis JPA 2 on peut restreindre à un type donné : select a from Article where type(a)

R. Grin JPA page 51

Polymorphisme dans les requêtes (2)

Depuis JPA 2 on peut restreindre à un type donné :select a from Article a where type(a) in (Stylo, Lot)

R. Grin JPA page 52

Expression de chemin

Les requêtes peuvent contenir des expressions de chemin pour naviguer entre les entités en suivant les associations déclarées dans le modèle objet (les annotations @OneToOne, @OneToMany, …)La notation « pointée » est utilisée

R. Grin JPA page 53

Règle pour les expressions de chemin

Une navigation peut être chaînée à une navigation précédente à la condition que la navigation précédente ne donne qu’une seule entité (OneToOne ou ManyToOne)Dans le cas où une navigation aboutit à plusieurs entités, il est possible d’utiliser la clause join étudiée plus loin pour obtenir ces entités

R. Grin JPA page 54

ExemplesSi e est un alias pour Employe, n « e.departement » désigne le

département d’un employén « e.projets » désigne la collection de

projets auxquels participe un employéselect e.nomfrom Employe as ewhere e.departement.nom = 'Qualité'

e.projets.nom n’est pas autorisé car e.projets est une collection (voir clause join)

Page 10: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

10

R. Grin JPA page 55

Autre exemple

select e.nom,e.departement.nom,e.superieur.departement.nom

from Employe e

R. Grin JPA page 56

distinct

Dans une clause select, indique que les valeurs dupliquées sont éliminées (la requête ne garde qu’une seule des valeurs égales)Exemple :select distinct e.departementfrom Employe e

R. Grin JPA page 57

new

Il est possible de renvoyer des instances d’une classe dont le constructeur prend en paramètre des informations récupérées dans la base de donnéesLa classe doit être désignée par son nom complet (avec le nom du paquetage)Exemple :select new p1.p2.Classe(e.nom, e.salaire)from Employe e

Group by

On peut regrouper sur un alias ou sur attribut ; on regroupe ici sur un alias :select d, count(e)from Departement d

join d.employes egroup by d

Les expressions du select (ou du order by s’il y en a un) qui ne sont pas des regroupements doivent se trouver aussi dans le group by, ce qui peut amener à ajouter une expression « inutile » dans le group by

R. Grin JPA page 58

R. Grin JPA page 59

Clauses where et having

Ces clauses peuvent comporter les mots-clés suivants :n [NOT] LIKE, [NOT] BETWEEN, [NOT] INn AND, OR, NOTn [NOT] EXISTSn ALL, SOME/ANYn IS [NOT] NULLn IS [NOT] EMPTY, [NOT] MEMBER OF (pour

les collections)

R. Grin JPA page 60

Exemple

select d.nom, avg(e.salaire)from Departement d join d.employes egroup by d.nomhaving count(d.nom) > 3

Page 11: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

11

R. Grin JPA page 61

having

Restriction : la condition doit porter sur une propriété ou une association à valeur unique de l’expression de regroupement (celle qui est dans le group by) ou sur une fonction de regroupementPar exempleselect e.nom, count(p)from Employe join e.projets pgroup by ehaving count(p) > 2

order byOn peut choisir un ordre dans les valeurs ou objets renvoyésEvidemment, il doit exister un ordre naturel dans les types utilisés pour le triIl peut y avoir plusieurs critères de triOn peut choisir un ordre croissant (par défaut) ou un ordre décroissant (critère de tri suivi de DESC)Le critère de tri ne peut être qu’une entité, un champ persistant ou un variable résultat (voir « gain » dans l’exemple du transparent suivant)

R. Grin JPA page 62

Exemple

select e from Employe eorder by e.nomselect e, d from Employe e join e.departement dorder by d.nom, e.nom descselect e.nom, e.salaire + e.prime as gainfrom Employeorder by gain

R. Grin JPA page 63

Restrictions

Si la clause select est une propriété, la clause order by ne peut utiliser que cette propriété ; la requête suivante est interdite :select e.nom from Employeorder by e.salaire

Un critère de tri ne peut comporter de fonction ; la requête suivante est interdite :select dfrom Departement d join d.employes eorder by avg(e.salaire)

R. Grin JPA page 64

R. Grin JPA page 65

Sous-requête (1)

Les clauses where et having peuvent contenir des sous-requêtesExemple :select e from Employe ewhere e.salaire >= (select e2.salaire from Employe e2where e2.departement = 10)

R. Grin JPA page 66

Sous-requête (2)

{ALL | ANY | SOME} (sous-requête) fonctionne comme dans SQLExemple :select e from Employe ewhere e.salaire >= ALL (select e2.salaire from Employe e2where e2.departement =

e.departement)

Page 12: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

12

R. Grin JPA page 67

Sous-requête synchronisée

Une sous-requête peut être synchronisée avec une requête englobanteExemple :select e from Employe ewhere e.salaire >= ALL (select e2.salaire from Employe e2where e2.departement =

e.departement)

R. Grin JPA page 68

Sous-requête - exists

[not]exists fonctionne comme avec SQLExemple :select emp from Employe ewhere exists (select ee from Employe eewhere ee = e.epouse)

R. Grin JPA page 69

Utilité de la jointure

« d.employes.nom » est interdit car d.employes est une collectionPour avoir les noms des employés d’un département, il faut utiliser une jointure

R. Grin JPA page 70

Jointure

Une jointure permet de combiner plusieurs entités dans un selectRappel : il est aussi possible d’utiliser plusieurs entités dans une requête grâce à la navigationUne jointure est le plus souvent utilisée pour résoudre les cas (interdit par JPA) oùn l’expression du select serait une collectionn la navigation partirait d’une collection

R. Grin JPA page 71

Types de jointures

Il existe plusieurs types de jointures :n jointure interne (jointure standard join)n jointure externe (outer join)n jointure avec récupération de données en

mémoire (join fetch)n jointure « à la SQL » dans un where pour

joindre suivant des champs qui ne correspondent pas à une association (where e1.f1 = e2.f2)

R. Grin JPA page 72

Exemple

Si on veut tous les employés d’un département, la requête suivante n’est pas permise par la spécification JPA :select d.employesfrom Departement dwhere d.nom = 'Direction'

Une jointure est nécessaire :select efrom Departement d join d.employes ewhere d.nom = 'Direction'

Page 13: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

13

R. Grin JPA page 73

Autres exemplesselect e.nomfrom Departement d

join d.employes ewhere d.nom = 'Direction'select e.nom, parts.projet.nomfrom Employe e

join e.participations parts select e.nom, d.nomfrom Employe e, Departement dwhere d = e.departementselect e, pfrom Employe e join e.participations partsjoin parts.projet p

R. Grin JPA page 74

Jointure externe

select e, dfrom Employe e left join e.departement dramènera aussi les employés qui ne sont pas associés à un département

Jointure « à la SQL »

Les jointures que nous avons vues s’appuient sur des associations entre entitésIl est aussi possible d’effectuer une jointure entre 2 entités sans s’appuyer sur une associationIl suffit d’indiquer les valeurs qui devront être égales dans la jointure

R. Grin JPA page 75

ExempleSoit une entité Candidature, sans association, qui contient des candidatures à des formationsL’entité contient les attributs suivants : id, nomP(identifie une personne), nomF (identifie une formation)Auto-jointure pour avoir la liste des personnes qui ont candidaté à plusieurs formations :select c0.nomP, c1.nomFfrom Candidature c0, Candidature c1where c0.nomP = c1.nomPand c0.nomF != c1.nomF

order by c0.nomP

R. Grin JPA page 76

R. Grin JPA page 77

join fetch

Permet d’éviter le problème des « N + 1 selects »Les entités placées à droite de join fetchseront créées en mémoire en même temps que l’entité de la clause select (mais pas renvoyées par la requête)Le select SQL généré sera une jointure externe qui récupérera les données de toutes les entités associées en même temps que les données des entités principales de la requête

R. Grin JPA page 78

Exemple

select efrom Employe e join fetch e.departement

Cette requête récupérera tous les employés mais, en plus, l’appel de la méthode getDepartement() ne provoquera aucune interrogation de la base de données puisque le « join fetch » aura déjà chargé tous les départements des employés

Page 14: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

14

R. Grin JPA page 79

Exemple

String texteQuery ="select e "+ " from Employe as e " + " join fetch e.participations";

Query query = em.createQuery(texteQuery);listeEmployes = (List<Employe>)query.getResultList();

Cet exemple précharge les participations aux projets des employés

R. Grin JPA page 80

Doublons possibles avec join fetchLa requête SQL lancée par un join fetch fait une jointure pour récupérer les entités préchargéesEnsuite, les entités préchargées sont enlevées des lignes du résultat pour qu’elles n’apparaissent pas dans le résultat du queryCe traitement, imposé par la spécification de JPA, peut occasionner des doublons dans le résultat si le select renvoie des valeurs (pas des entités)Pour les éviter, il faut ajouter l’opérateur DISTINCT dans le texte de la requête ou placer le résultat dans une collection de type Set

R. Grin JPA page 81

Il existe aussi des variantes « outer join » de join fetch pour récupérer dans le select des entités non jointes à une autre entité

R. Grin JPA page 82

Produit cartésien (1)

Le préchargement par join fetch de plusieurscollections d’une même entité peut occasionner un phénomène nuisible aux performancesEn effet, le select SQL généré par le fournisseur de persistance peut récupérer un produit cartésien des éléments des collectionsLe fournisseur s’arrange pour ne garder que les informations nécessaires mais le select peut renvoyer un très grand nombre de lignes qui vont transiter par le réseau

R. Grin JPA page 83

Produit cartésien (2)Dans le cas où les collections contiennent de nombreux éléments il faut donc vérifier avec les logs du fournisseur si le select généré renvoie effectivement un trop grand nombre de lignes et changer de stratégie de récupération si c’est le cas (récupérer séparément les informations sur les collections)En effet, si 2 collections contiennent 20 éléments, et si 1000 entités principales sont renvoyées le select renverra 400.000 lignes ! (au lieu de 40.000 si on ramène les informations avec 2 join fetch séparés)

R. Grin JPA page 84

ExempleUne entité principale ep avec 2 associations de l’entité principale avec d’autres entités e2 et e3Pour récupérer en mémoire les entités principales et associées, le select généré risque d’être du type suivant (consulter les logs du fournisseur de persistance) :select ep.*, e2.*, e3.*from EP epleft outer join E2 e2 on ep.id_e2 =

e2.idleft outer join E3 e3 on ep.id_e3 =

e3.id

Page 15: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

15

R. Grin JPA page 85

FonctionsPour les chaînes de caractères : concat, substring, trim, lower, upper, length, locate (localiser une sous-chaîne dans une autre)Arithmétiques : abs, sqrt, mod, size (d’une collection)Pour les date : current_date, current_time, current_timestampDe regroupement : count, max, min, avg« Conditionnelles » : case, coalesce, nullifqui sont les pendants des fonctions SQL

case

JPA 2.0 a introduit le case de SQL (peut être utilisé dans une clause where ou having ou même dans un update (voir section suivante)Variante « simple » :CASE valeurWHEN valeur1 THEN résultat1WHEN valeur2 THEN résultat2…ELSE résultatN

END

valeur peut être un attribut ou une expression de type

R. Grin JPA page 86

case

Variante « généraleCASEWHEN condition1 THEN résultat1WHEN condition2 THEN résultat2…ELSE résultatN

END

R. Grin JPA page 87

Exemples de caseselect a.description,case type(a)when Stylo then 'stylo'when Ramette then 'ramette'else 'autre type'

endfrom Article aupdate Employe eset e.salaire = case e.indicewhen 1 then e.salaire * 1.1else e.salaire * 1.2

endR. Grin JPA page 88

coalesce

coalesce(expression1, expression2,...)renvoie la valeur de la 1ère expression non égale à nullExemple : coalesce(commission, salaire, 0)renvoie la valeur de la commission si elle n’est pas null, sinon renvoie la valeur s’il n’est pas null, et renvoie 0 sinon

R. Grin JPA page 89

nullif

nullif(expression1, expression2) renvoie null si les 2 expressions sont égales, sinon renvoie la valeur de expression1Peut servir pour une ancienne base de données dans laquelle les valeurs « null » sont en fait représentées par une certaine valeurExemple : nullif(salaire, -1)

R. Grin JPA page 90

Page 16: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

16

Fonction index

JPA 2.0 permet de conserver l’ordre d’une liste grâce à une colonne de la BDLa fonction index retourne la valeur de cette colonne (0 pour le 1er élément) Exemple :select e.nom, t.numerofrom Employe e join e.telephones twhere index(t) = 0affiche les noms des employés avec leur numéro de téléphone classé 1er dans la liste de leurs numéro de téléphone

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

Travail avec les collectionsUne expression chemin d’un select peut désigner une collectionExemples : departement.employesfacture.lignesLa fonction size donne la taille de la collectionLa condition « is [not] empty » est vraie si la collection est [n’est pas] videLa condition « [not] member of » indique si une entité appartient à une collection

R. Grin JPA page 93

Exemples

select dfrom Departementwhere e.employes is emptyselect efrom Employe ewhere :projet member of e.participations.projet

R. Grin JPA page 94

Parcours d’une collection

La requête suivante ne donnera pas tous les produits liés à une facture ; elle provoquera une exception à l’exécutionselect distinct f.lignes.produitfrom Facture as f

En effet, il est interdit de composer une expression de chemin en partant d’une expression qui désigne une collection (f.lignes)

R. Grin JPA page 95

Parcours d’une collection

Le plus simple est d’utiliser un join dans le from avec un alias (« l » dans l’exemple ci-dessous) pour désigner un élément qui parcourt la collection :select distinct l.produitfrom Facture as f join f.lignes as l

L’autre solution, « in », une ancienne syntaxe héritée d’EJB 2, n’est pas recommandée

R. Grin JPA page 96

API « critères »

Page 17: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

17

IntroductionAPI introduite par JPA 2.0Tout ce qui peut être fait avec JPQL peut l’être avec l’API « critères »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 compilationL’inconvénient est que le code est un peu plus complexe à écrire, et sans doute moins lisible

R. Grin JPA page 97

Métamodèle

Le métamodèle un ensemble de classes qui représente les classes gérées par le manager d’entités ainsi que leur état (leurs attributs) et les associations entre elles L’API critère peut s’utiliser de avec ou sans utilisation explicite du métamodèleL’utilisation explicite du métamodèlecomplique un peu l’écriture des requêtes mais permet de détecter plus d’erreurs à la compilation

R. Grin JPA page 98

Obtenir le métamodèle d’une classe

Dynamiquement en partant de Root :Root<Dept> dept = cq.from(Dept.class);EntityType<Dept> Dept_ = dept.getModel();

Dynamiquement en récupérant le métamodèle :EntityMananger em = …;Metamodel m = em.getMetamodel();EntityType<Dept> Dept_ = m.entity(Dept.class);

Statiquement (voir transparents suivants)R. Grin JPA page 99

Métamodèle canonique (1/2)

Les environnements de programmation pour JPA ou des fournisseurs de persistance offrent un programme qui permet de générer statiquement les classes du métamodèle (sinon le développeur peut les écrire lui-même)Les classes générées ont pour nom le nom des classes gérées suffixé par « _ » : Employe_pour représenter l’entité Employe

R. Grin JPA page 100

Métamodèle canonique (2/2)

Ces classes ont des variables de classe pour chacune des propriétés des classes gérées qui servent dans les requêtes : Employe_.nom, ce qui permettra de détecter encore plus d’erreurs à la compilation dans les requêtes qu’avec le métamodèle obtenu dynamiquementLes exemples suivants comparent 4 façons d’exécuter une requête : avec JPQL, sans métamodèle, avec un métamodèle dynamique et avec le métamodèle canonique statique

R. Grin JPA page 101

Exemple de classe du méta-modèle canonique

@StaticModel(Employe.class)public class Employe_ {

public static volatile SingularAttributes<Employe, Integer> id;

public static volatile SingularAttributes<Employe, String> nom;

public static volatile SingularAttributes<Employe, Departement> dept;

public static volatile CollectionAttributes<Employe, Projet> projets;

// D’autres « public static volatile ... »...

}R. Grin JPA page 102

Page 18: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

18

Avec JPQL

String s ="select e from Employe e where e.nom = ‘Dupond’";

Query query = em.createQuery(s);Employe emp = (Employe)query.getSingleResult();

R. Grin JPA page 103

API critère sans métamodèle

CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Employe> cq = cb.createQuery(Employe.class);

Root<Employe> emp = cq.from(Employe.class);cq.select(emp).where(cb.equal(emp.get("nom"), "Bob"));

TypedQuery<Employe> tq = em.createQuery(cq);Employe dupond = tq.getSingleResult();

R. Grin JPA page 104

Métamodèle dynamiqueCriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Employe> cq = cb.createQuery(Employe.class);

Root<Employe> emp = cq.from(Employe.class);EntityType<Employe> employe_ = emp.getModel();cq.select(emp).where(cb.equal(emp.get(employe_.getSingularAttribute("nom")),

"Dupond"));TypedQuery<Employe> tq = em.createQuery(cq); Employe dupond = tq.getSingleResult();

R. Grin JPA page 105

Métamodèle canonique statique

CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Employe> cq = cb.createQuery(Employe.class);

Root<Employe> emp = cq.from(Employe.class);cq.select(emp).where(cb.equal(emp.get(Employe_.nom),

"Dupond"));TypedQuery<Employe> tq = em.createQuery(cq);Employe dupond = tq.getSingleResult();

R. Grin JPA page 106

API complexe

L’API contient de nombreuses interfaces et ne peut être détaillée dans ce coursNous n’en donnerons qu’un aperçu avec 2 exemples

R. Grin JPA page 107

Exemple (sans métamodèle)CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Employe> cq =

cb.createQuery(Employe.class);Root<Employe> emp = cq.from(Employe.class);cq.select(emp).

where(cb.ge(emp.get("salaire").as(Double.class), 5000.0));

R. Grin JPA page 108

Cast obligatoire

Page 19: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

19

Exemple plus complexeCriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<String> cq =

cb.createQuery(String.class); Root<Client> client = cq.from(Client.class);Join<Facture,LigneFacture> ligne =

client.join(Client_.factures).join(Facture_.lignesFacture);

cq.where(qb.equals(ligne.get(ligne_.produit).get(Produit_.typeProduit), "imprimante")).select(client.get(Client_.nom));

R. Grin JPA page 109

select c.nomfrom Client c join c.factures f join f.lignes lwhere l.produit.typeProduit = 'imprimante'

En JPQL :

R. Grin JPA page 110

Opérations de modification en volume

R. Grin JPA page 111

Utilité

Pour les performances il est parfois mauvais de charger toutes les données à modifier dans des instances d’entitésEn ce cas, JPQL permet de modifier les données de la base directement, sans créer les entités correspondantes

R. Grin JPA page 112

Cas d’utilisationSi on veut augmenter de 5% les 1000 employés de l’entreprise il serait mauvais de récupérer dans 1000 instances les données de chaque employés, de modifier le salaire de chacun, puis de sauvegarder les donnéesUn simple ordre SQLupdate employeset salaire = salaire * 1.05sera énormément plus performantJPQL permet de lancer cet ordre sans passer par JDBC

R. Grin JPA page 113

Exempleem.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 114

SyntaxeLes ordres de modification en volume référencent les classes et les propriétés des classes mais ils ne créent aucune entité en mémoire et ils ne mettent pas à jour les entités déjà présentes en mémoireupdate Entite as aliasset alias.prop1 = val1, alias.prop2 = val2,…where conditionLa condition peut être aussi complexe que la condition d’un select

Page 20: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

20

R. Grin JPA page 115

RemarquesLes modifications doivent être faites dans une transactionLe plus souvent il faut isoler le lancement de ces opérations dans une transaction à part, ou au moins exécuter ces opérations au début d’une transaction avant la récupération dans la base d’entités touchées par l’opérationEn effet, les entités en mémoire ne sont pas modifiées par l’opération et elles ne correspondront alors donc plus aux nouvelles valeurs modifiées dans la base de données

Version des entités

Les versions des entités modifiées par les modifications en volume ne sont pas nécessairement mises à jour (dépend des fournisseurs de persistance, donc pas portable)Il peut donc être nécessaire d’incrémenter explicitement le numéro de version dans le update

R. Grin JPA page 116

R. Grin JPA page 117

Exceptions

R. Grin JPA page 118

Exceptions utilisées par JPA

JPA n’utilise que des exceptions non contrôlées(descendantes de RuntimeException)JPA utilise les 2 exceptions IllegalArgumentException et IllegalStateException du paquetage java.lang

Sinon, toutes les autres exceptions sont dans le paquetage javax.persistence et héritent de PersistenceException

R. Grin JPA page 119

Types d’exception

NonUniqueResultExceptionNoResultExceptionEntityNotFoundExceptionEntityExistsExceptionTransactionRequiredExceptionRollbackExceptionOptimisticLockExceptionPessimisticLockExceptionLockTimeoutException

R. Grin JPA page 120

PersistenceException et rollbackToute les exceptions de type PersistenceException marquent la transaction en cours pour un rollback (voir section suivante sur les transactions), sauf NoResultException,NonUniqueResultException (toutes les 2 liées à getSingleResult) et LockTimeoutException

Page 21: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

21

Exceptions dans les méthodes d’accès aux propriétés

Les RuntimeException marquent la transaction en cours pour un rollbackLes exception contrôlées sont enveloppées dans une PersistenceException (non contrôlée) et la transaction en cours est marquée pour un rollback

R. Grin JPA page 121 R. Grin JPA page 122

Transaction

R. Grin JPA page 123

2 types de transactions

Les transactions locales à une ressource, fournies par JDBC sont attachées à une seule base de donnéesLes transactions JTA, ont plus de fonctionnalités que les transactions JDBC ; en particulier des opérations effectuées dans plusieurs bases de données peuvent être englobées dans une seule transaction

R. Grin JPA page 124

Transactions dans Java EE

Elles ne sont pas étudiées dans ce cours

R. Grin JPA page 125

Transactions dans Java SE(sans serveur d’applications)

D’après la spécification JPA, dans Java SE, les fournisseurs de persistance doivent supporter les transactions locales à une ressource, mais ne sont pas obligés de supporter les transactions JTALa démarcation des transactions est choisie par le développeurLes contextes de persistance peuvent couvrir plusieurs transactions

R. Grin JPA page 126

EntityTransaction

En dehors d’un serveur d’application, une application doit utiliser l’interface javax.persistence.EntityTransactionpour travailler avec des transactions locales à une ressourceUne instance de EntityTransaction peut s’obtenir par la méthode getTransaction()de EntityManager

Page 22: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

22

R. Grin JPA page 127

EntityTransaction

public interface EntityTransaction {public void begin();public void commit();public void rollback();public void setRollbackOnly();public boolean getRollbackOnly();public boolean isActive();

}

R. Grin JPA page 128

Exemple

EntityManager em;...try {em.getTransaction().begin()...em.getTransaction().commit();

}finally {em.close();

}

R. Grin JPA page 129

Rollback (1)

En cas de rollback,n rollback dans la base de donnéesn le contexte de persistance est vidé ; toutes

les entités deviennent détachées

R. Grin JPA page 130

Rollback (2)

Les instances d’entités Java gardent les valeurs qu’elles avaient au moment du rollbackMais ces valeurs sont le plus souvent faussesIl est donc rare d’utiliser ces entités en les rattachant par un merge à un GELe plus souvent il faut relancer des requêtes pour récupérer des entités avec des valeurs correctes

R. Grin JPA page 131

Transaction et contexte de persistance

Quand un GE n’est pas géré par un container (c’est le cas en dehors d’un serveur d’application) le contexte de persistance n’est pas fermé à la fin d’une transactionQuand un GE est géré par un container (c’est le cas avec un serveur d’application) et que le contexte de persistance n’est pas de type « étendu » (pas étudié dans ce cours), le contexte est fermé à la fin d’une transaction

R. Grin JPA page 132

Synchronisation d’un GE avec une transaction

Synchronisation d’un GE avec une transaction : le GE est enregistré auprès de la transaction ; un commit de la transaction provoquera alors automatiquement un flush du GE (le GE est averti lors du commit)En dehors d’un serveur d’application (avec Java SE), un GE est obligatoirement synchronisé avec les transactions (qu’il a lancées par la méthode begin() de EntityTransaction)

Page 23: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

23

R. Grin JPA page 133

Modifications et commit

Les modifications effectuées sur les entités gérées sont enregistrées dans la base de données au moment d’un flush du contexte de persistanceSi le GE est synchronisé à la transaction en cours, le commit de la transaction enregistre donc les modifications dans la baseLes modifications sont enregistrées dans la base, même si elles ont été effectuées avant le début de la transaction (avant tx.begin()dans Java SE)

Erreurs et problèmes divers

Démarrer une nouvelle transaction alors qu’il y en a déjà une en cours lancera une IllegalStateExceptioncommit() et rollback() lancent la même exception si aucune transaction n’est activeSi une erreur survient lors de rollback(), une PersistanceException sera lancéeSi une erreur survient lors de commit(), une RollbackException est lancée

R. Grin JPA page 134

Marquage pour un rollback (1)

Dans les applications d’entreprise, les transactions sont souvent gérées par un serveur d’application qui effectue lui-même les commit et rollbackLe code de l’application ne peut lancer de commit ou de rollback ; il peut cependant marquer la transaction pour un rollback par la méthode setRollbackOnly()Le serveur d’application est alors obligé de terminer la transaction par un rollback

R. Grin JPA page 135

Marquage pour un rollback (2)

Le plus souvent la méthode setRollbackOnly est appelée dans un bloc catch lorsqu’une exception s’est produitePlus généralement elle peut être appelée lorsqu’une condition quelconque ne permet pas que la transaction soit validéeIl est impossible d’enlever une marque pour un rollback

R. Grin JPA page 136

Marquage pour un rollback (3)

Cette méthode (ainsi que la méthode getRollbackOnly) ne doivent pas être utilisées dans le cas où l’application gère elle-même les transactionsC’est le cas en particulier des applications qui ne sont pas gérées par un serveur d’application ; ces 2 méthodes sortent donc du cadre fixé pour ce cours

R. Grin JPA page 137

Exceptions et transactions

Il faut prendre garde de ne pas laisser des transactions ouvertes dans le cas où des flushs ont transféré des commandes vers la base de donnéesEn effet, les blocages effectués dans la base de données ne seront alors pas libérésUne cause d’erreur peut être la levée d’une exception qui fait sortir d’une méthode, et dont le traitement ne ferme pas la transaction en cours (par commit ou rollback)

R. Grin JPA page 138

Page 24: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

24

R. Grin JPA page 139

Concurrence

R. Grin JPA page 140

GE et threads

Une fabrique de GE peut être utilisée sans problème par plusieurs threadsMais un GE ne doit être utilisé concurremment que par un seul thread

R. Grin JPA page 141

Entités et threads

Les entités ne sont pas prévues pour être utilisées par plusieurs threads en même tempsSi ça doit être le cas, l’application doit prendre toutes ses précautions pour éviter les problèmesC’est aussi le rôle de l’application d’empêcher qu’une entité ne soit gérée par plusieurs GE en même tempsLe rôle du fournisseur de persistance n’intervient pas pour ces cas

R. Grin JPA page 142

Concurrence « BD »

Le fournisseur de persistance peut apporter automatiquement une aide pour éviter les problèmes d’accès concurrents aux données de la BD, pour les entités gérées par un GE

R. Grin JPA page 143

Exemple de problème de concurrence « BD »

Une entité est récupérée depuis la BD (par un find par exemple)L’entité est ensuite modifiée par l’application puis la transaction souhaite valider cette modificationSi une autre transaction a modifié entre-temps les données de la BD correspondant à l’entité, la transaction ne doit pas être validée pour éviter les problèmes de mises à jour perdues

R. Grin JPA page 144

Gestion de la concurrence

JPA suppose aussi que la BD a le mode d’isolation « READ COMMITED » (voir cours sur les BD) et que les écritures dans la base n’ont lieu qu’au moment d’un flushPar défaut (sans aucun blocage explicite par lock), le fournisseur de persistance gère les problèmes d’accès concurrents aux entités gérées par un GE, qui ont un attribut « version », avec une stratégie optimiste

Page 25: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

25

R. Grin JPA page 145

@Version (1/2)

Annote un attribut dont la valeur représente un numéro de version (incrémenté à chaque modification), utilisé pour savoir si l’état d’une entité a été modifié entre 2 moments différentsCorrespond à une colonne de la base de donnéesLa valeur de l’attribut et de la colonne de la base de données sont mises à jour automatiquement par JPA

R. Grin JPA page 146

@Version (2/2)L’attribut doit être de type int, Integer, short, Short, long, Long ou java.sql.TimeStamp (si possible, éviter ce dernier type) et ne doit pas être null dans la base de données« Entité versionnée » : possède un attribut annoté @Version (ou le tag correspondant dans les fichiers XML)

R. Grin JPA page 147

Exemple

@Versionprivate int version;

R. Grin JPA page 148

Modification automatiquede la version

La version est mise à jour automatiquement n si le champ modifié est un champ « ordinaire » n ou un champ lié à une association dont l’entité

possède la clé étrangère (elle en est donc propriétaire)

JPA n’impose pas que la version soit mise à jour lors d’une opération de modifications en volume

R. Grin JPA page 149

Modification de la version

L’application ne doit jamais modifier un tel attribut (seul JPA le modifie), sauf, éventuellement lors des opérations de modifications en volumeSi on veut mettre à jour la version dans le cas d’une association dont l’entité ne possède pas la clé étrangère, il faut utiliser lock avec l’option d’incrément de la version (étudié ci-après)

R. Grin JPA page 150

Protection par défaut des entités « versionnées »

Même sans aucun blocage explicite, JPA protège les données contre les accès concurrentCette protection minimale empêche la situation suivante : une transaction t1 ne pourra valider des modifications sur des données lues dans la base que si ces données n’ont pas été modifiées par une autre transaction entre le moment où t1 les a lues et le moment où elle lance un commit

Page 26: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

26

R. Grin JPA page 151

Protection des entités « non versionnées »

Le fournisseur de persistance peut aussi effectuer automatiquement ce contrôle sur une entité non versionnée (par exemple en comparant les données lues avec les données de la base au moment du commit), mais JPA ne l’impose pasPour la portabilité il faut donc versionner les entités sujettes à des accès concurrents (ou utiliser les blocages pessimistes)

R. Grin JPA page 152

Exception

Si la transaction est invalidée en liaison d’un blocage optimiste, une exception OptimisticLockException est lancée

R. Grin JPA page 153

lock(entite, mode)

Sert à protéger une entité contre les accès concurrents pour les cas où la protection offerte par défaut ne suffit pas (on a vu que, même sans aucun blocage explicite avec lock, JPA protège déjà des accès concurrents avec une stratégie optimiste)Cette entité doit être versionnée (sinon, le traitement n’est pas portable) et déjà gérée par le gestionnaire d’entités

Autres méthodes pour le blocage

Il est possible d’indiquer un mode de blocage pour les entités ramenées par un find (en 3ème paramètre de la méthode) ou un query(méthode setLockMode de l’interface Query)refresh permet aussi d’indiquer un blocage pour l’entité dont on rafraîchit l’état (en 2ème

paramètre)Ces méthodes doivent être lancées dans une transaction (à part setLockMode, mais le query doit être lancé dans une transaction)

R. Grin JPA page 154

R. Grin JPA page 155

Modes de blocage

L’énumération LockModeType (paquetage javax.persistence) définit 5 modes n OPTIMISTIC (READ en JPA 1)n OPTIMISTIC_FORCE_INCREMENT (WRITE

en JPA 1)n PESSIMISTIC_READn PESSIMISTIC_WRITEn PESSIMISTIC_FORCE_INCREMENT

R. Grin JPA page 156

Modes de blocage optimistesOPTIMISTIC : si une autre transaction modifie l’entité bloquée, la transaction t1 qui a bloqué l’entité s’apercevra que le numéro de version a changé et sera invalidée, même t1 n’a pas modifié la donnéeOPTIMISTIC_FORCE_INCREMENT : comme OPTIMISTIC, mais en plus l’attribut de version de l’entité bloquée est incrémenté, même si l’entité n’a pas été modifiée par la transaction t1 (utilité expliquée dans les transparents suivants

Page 27: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

27

Différence avec le traitement par défaut

L’invalidation de la transaction arrivera même si l’entité bloqué par un lock OPTIMISTIC n’a pas été modifiée par la transaction

R. Grin JPA page 157 R. Grin JPA page 158

Utilité du blocage OPTIMISTICCe blocage est utile pour faire des bilans pour lesquels les données ne doivent pas être modifiées du début à la fin du traitementIl peut aussi être utile si 2 valeurs sont étroitement liées de telle sorte que la modification d’une des valeurs par une transaction T empêche la modification de l’autre par une autre transaction ; pour modifier une des 2 valeurs, T doit alors bloquer aussi l’autre valeur, même si celle-ci n’est pas modifiée par la transaction T

R. Grin JPA page 159

Un exemple (1)Un bilan qui calcule le total des salaires des employés pour chaque département doit interdire qu’un employé ne change de département pendant le traitement, en passant du département 10 au département 20Sinon, cet employé sera compté 2 fois : après avoir fait le calcul du total du département 10, on va faire une requête pour récupérer les employés du département 20 et retrouver l’employé déjà décompté dans le département 10

R. Grin JPA page 160

Un exemple (2)

Pour éviter ce problème, les employés peuvent être bloqués en mode OPTIMISTIC, au fur et à mesure de leur prise en compte pour le calcul du total des salaires de leur département

R. Grin JPA page 161

OPTIMISTIC_FORCE_INCREMENT

Force une incrémentation du numéro de versionPour certains traitements il est intéressant de considérer que l’entité a été modifiée même si aucun de ses attributs n’a été modifié, par exemple lorsqu’une association avec une autre entité a été modifiéeDans l’exemple qui suit, le blocage OPTIMISTIC_FORCE_INCREMENT évite en quelque sorte les problèmes de lignes fantômes avec les associations qui concernent une entité

R. Grin JPA page 162

OPTIMISTIC_FORCE_INCREMENT

En effet, sans le blocage OPTIMISTIC_FORCE_INCREMENT (« OFI » pour la suite), le fournisseur de persistance incrémente automatiquement le numéro de version si une entité est modifiée mais pas si les liens des associations qui partent de l’entité sont modifiées lorsque l’entité n’est pas propriétaire de l’association (voir cependant la remarque qui suit l’exemple donné dans les transparents suivants)

Page 28: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

28

R. Grin JPA page 163

Utilité des blocages OFI (1)

Une en-tête de facture contient un champ dans lequel est stocké le total de la factureSupposons que le calcul de ce total est effectué par un processus à part du processus de l’ajout des lignes de la factureLorsqu’une ligne de facture est ajoutée à une facture, l’en-tête de la facture n’est pas modifiée donc le fournisseur de persistance n’incrémente pas le numéro de version de l’en-tête

R. Grin JPA page 164

Utilité des blocages OFI (2)

Une ligne peut être ajoutée à une facture sans que le traitement qui calcule le total ne s’en rende compte ; il y aura inconsistance entre ce total et les lignes de la factureSi l’en-tête est bloquée en écriture pendant l’ajout d’une ligne de facture, le traitement qui effectue le calcul du total s’apercevra que la facture a changé pendant le calcul puisque le numéro de version aura été incrémenté et il n’y aura pas inconsistance

R. Grin JPA page 165

Remarque

Certains fournisseurs de persistance comme Hibernate incrémentent le numéro de version quand les collections d’une entité sont modifiéesDans ce cas le blocage OFI sera tout de même utile si, par exemple, un des éléments de la collection est modifié, par exemple le prix d’un produit compris dans la facture

Blocages pessimistes (1/3)

Lorsque la probabilité de conflits est trop importante, la stratégie optimiste conduit à de trop nombreux rollbackEn ce cas il vaut mieux bloquer dès le début l’accès des autres transactions aux données que l’on manipuleJPA 2.0 a ajouté des blocages pessimistesComme les blocages optimistes, ils permettent d’éviter les lectures non répétables

R. Grin JPA page 166

Blocages pessimistes (2/3)

Le blocage dure jusqu’à la fin de la transactionAucune autre transaction du SGBD sous-jacent ne pourra modifier ou supprimer les données bloquéesSi le blocage est FORCE_INCREMENT ou WRITE, la transaction qui a bloqué pourra modifier ou supprimer les données bloquées (un blocage READ peut être partagé avec une autre transaction et donc empêcher la transaction de modifier les données)

R. Grin JPA page 167

Blocages pessimistes (3/3)

Les versions des entités bloquées en mode pessimiste et modifiées sont incrémentées

R. Grin JPA page 168

Page 29: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

29

Portée du blocageL’énumération PessimisticLockScopecontient les 2 valeurs NORMAL et EXTENDEDEn mode EXTENDED, les données correspondant à une association ou à une collection d’éléments, qui sont dans une table jointe, sont aussi bloquéesLa portée peut être indiquée avec la propriété javax.persistence.lock.scope dans différentes méthodes des classes EntityManager et Query comme la méthode lock(entité, mode, propriétés)

R. Grin JPA page 169

Modes de blocage pessimistes

PESSIMISTIC_WRITE : le mode le plus courant ; les données de la base correspondant aux entités bloquées ne pourront être modifiées par d’autres transactions ; blocage exclusifPESSIMISTIC_READ : assure des lectures répétables ; blocage partageablePESSIMISTIC_FORCE_INCREMENT : comme WRITE avec, en plus, la mise à jour de la version, même si l’entité n’a pas été modifiée

R. Grin JPA page 170

PESSIMISTIC_WRITE

L’entité est bloquée (pour les autres transaction) dès sa modification par la transaction qui a lancé le lock ; correspond à un select for update dans la base de donnéesEmpêche les autres transactions de bloquer en mode PESSIMISTIC_READ ou _WRITE(jusqu’à la fin de la transaction)Les autres transactions devront attendre la fin de la transaction pour pouvoir à leur tour modifier l’entité

R. Grin JPA page 171

PESSIMISTIC_READ

Mode utilisé par certaines bases de données pour empêcher les lectures non répétables, sans bloquer par un select for updateLes autres transactions ne peuvent modifier les données qui correspondent à l’entité mais peuvent les lireEmpêche les autres transactions de bloquer en mode PESSIMISTIC_WRITE mais pas de bloquer en mode PESSIMISTIC_READ

R. Grin JPA page 172

Changement automatique de mode

Lorsqu’une transaction a bloqué une entité en mode PESSIMISTIC_READ et qu’elle modifie ensuite l’entité, le mode passe automatiquement en PESSIMISTIC_WRITE

R. Grin JPA page 173

Exception

Lorsque le fournisseur de persistance ne peut obtenir un blocage pessimiste et que le SGBD sous-jacent ne fait qu’un rollback de la requête (et pas de la transaction toute entière), une LockTimeoutException doit être lancée et la transaction ne doit pas être marquée pour un rollbackSi le problème est plus grave, une PessimisticLockException est lancée et la transaction est marquée pour un rollback

R. Grin JPA page 174

Page 30: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

30

R. Grin JPA page 175

Entité détachée

R. Grin JPA page 176

Les entités détachées sont surtout utiles dans les applications multi-tiers (avec Java EE et un serveur d’applications)Cette section survole les possibilités offertes par les entités détachées

R. Grin JPA page 177

Cas d’utilisation des entités détachées

Une application multi-tiersLe serveur d’application récupère des données dans la BDCes données sont passées à la couche client, montrées à l’utilisateur qui peut les modifierLes modifications sont repassées au serveur et enregistrées dans la BDLes entités détachées facilitent l’implémentation d’un tel cas d’utilisation

R. Grin JPA page 178

Utilisation des entités détachées

Une fois détachées les entités peuvent être passées à la couche clienteLa couche cliente peut modifier les entités détachéesCes entités peuvent ensuite être rattachées à un GE et les modifications effectuées dans la couche cliente peuvent être alors enregistrées dans la base de données lors d'un flush

R. Grin JPA page 179

Rattachement

La méthode merge de EntityManagerpermet d’obtenir une entité gérée à partir d’une entité détachéeSa signature :<T> T merge(T entité)

Attention, l’entité passée en paramètre n’est pas rattachée ; c’est l’entité renvoyée par la méthode merge qui est rattachée ; cette entité a le même état et la même clé primaire que l’entité passée en paramètre

R. Grin JPA page 180

Si l’entité passée en paramètre de merge est déjà gérée par le GE (c’est l’identificateur de l’entité qui permet de savoir si l’entité est déjà gérée), ses valeurs sont écrasées par les valeurs de l’objet passé en paramètre et elle est renvoyée par la méthode merge

Page 31: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

31

R. Grin JPA page 181

État d’une entité détachée

L’état d’une entité détachée peut ne pas être entièrement disponible

R. Grin JPA page 182

État d’une entité

Pour des raisons de performances, l'état d’une entité gérée par un GE peut ne avoir été complètement récupéré dans la BD (récupération retardée ; lazy)Le reste de l’état ne sera récupéré, avec l’aide du GE, que lorsque l’entité en aura vraiment besoinSi l’entité est détachée alors qu’une partie de son état n’a pas encore été récupérée, la partie manquante de l’entité détachée ne sera pas disponible

R. Grin JPA page 183

Attribut disponible

Un attribut persistant d’une entité est immédiatement disponible dans les 2 cas suivants :n l’attribut a déjà été utilisén l’attribut n’a pas été marqué par fetch=LAZY(par défaut, les valeurs des attributs sont chargées en mémoire)

R. Grin JPA page 184

Association d’une entité détachée

Si une association d’un objet détaché a le mode de récupération LAZY, il est possible que l’association ne puisse être récupérée (dépend des circonstances et des fournisseurs de JPA)

R. Grin JPA page 185

Association « lazy » disponible

Si une association d’un objet détaché a le mode de récupération LAZY, il est possible de naviguer à travers cette association si n l’application a déjà effectué cette

navigationn ou si l’association a été chargée par un join fetch lors d’une requête

R. Grin JPA page 186

Rendre accessible l’état d’une entité détachée

2 solutions pour accéder à tout l’état (valeurs dans la base de données) d’une entité détachéeL’application récupère tout l’état de l’entité gérée avant le détachementL’application rattache l’entité par la méthode merge le temps de récupérer l’état manquant

Page 32: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

32

R. Grin JPA page 187

Récupérer une association avant le détachement

Si le but est une entité (OneToOne ou ManyToOne), il suffit de lire une des propriétés de l’entitéSi le but est une collection (OneToMany ou ManyToMany), l’appel de la méthode size()de la collection suffit le plus souvent

R. Grin JPA page 188

Entité détachée et concurrence

Avant que les modifications sur l’entité détachée ne soient enregistrées dans la BD, l’entité doit être rattachée à un contexte de persistance (celui d’origine ou un autre)A ce moment, ou au moment du commit qui enregistre vraiment les modifications, le contexte de persistance vérifie qu’il n’y a pas de conflit de concurrence

R. Grin JPA page 189

Conflit de concurrence

Si les données de la BD associée à un objet détaché ont été modifiées depuis le détachement de l’objet, merge lance une exceptionTout se passe donc comme si un conflit de concurrence avait été détecté (avec une stratégie optimiste)

R. Grin JPA page 190

Détachement automatique

Dans Java SE, quelques situations provoquent un détachement automatique des entités gérées :n Après un rollbackn Après un clear du GEn Après la fermeture du GEnUn nouvel objet créé à partir à partir d’une

entité sérialisée est détaché (situation fréquente pour les applications distribuées)

R. Grin JPA page 191

Configuration d’une unité de persistance

R. Grin JPA page 192

Fichiers de configuration

Pour fonctionner JPA a besoin de n savoir comment se connecter à la base de donnéesn avoir les informations pour faire le mapping entre les

classes entités et les tables de la baseLes informations sur la base de données sont données le plus souvent par le fichier META-INF/persistence.xmlLes informations sur le mapping sont données le plus souvent par des annotations mais elles peuvent aussi être données par le fichierMETA-INF/orm.xml

Page 33: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

33

Ces informations sont lues au moment où une fabrique de gestionnaire d’entités est créée

R. Grin JPA page 193 R. Grin JPA page 194

Fichier persistence.xml

Les informations hors mapping sont données le plus souvent dans un fichier persistence.xmlDans un environnement non géré, ce fichier doit se situer dans le répertoire META-INF d’un des répertoires du classpathDans un serveur d’applications, le répertoire META-INF peut se trouver à divers endroits : dans WEB-INF/classes, un fichier jar de WEB-INF/lib, un fichier jar de la racine d’un fichier EAR,… (voir spécification pour la liste complète)

R. Grin JPA page 195

Configuration dans unenvironnement non géré

Dans un environnent non géré par un serveur d’applications, il est nécessaire de donner les informations pour la connexion à la base de donnéesSouvent une application n’utilise qu’un seul compte utilisateur dans la base de données ; en ce cas, le nom et le mot de passe de ce compte sont donnés dans le fichier persistence.xml

R. Grin JPA page 196

Configuration dans unenvironnement géré

Dans un environnent géré, la source de données est le plus souvent déjà définie dans le serveur d’applications et il suffit alors de donner le nom (JNDI) de la source de données dans le fichier persistence.xml

Il est cependant possible aussi de définir la source de données dans l’application avec l’annotation @DataSourceDefinition, au lieu de la définir d’abord dans le serveur d’application

R. Grin JPA page 197

Fichier persistence.xml

Le fichier persistence.xml peut aussi donner d’autres informations, comme n les noms des classes « gérées » dont les attributs

seront enregistrés dans la base (entités, classes Embeddable, classes « mapped superclasses ») ; c’est obligatoire dans un environnement non géré par un serveur d’application

n la configuration de l’environnement de mis au point (enregistrement dans les journaux/logging, affichage des ordres SQL lancés dans le SGBD,…)

n des propriétés particulières au driver du fournisseur de persistance

R. Grin JPA page 198

persistence.xml<persistencexmlns="http://java.sun.com/xml/ns/persistence"version= "1.0" ><persistence-unit name="Employes"

transaction-type="RESOURCE_LOCAL"><class>p1.Employe</class><class>p1.Dept</class><properties>

. . . <!– Voir transparent suivant--></properties>

</persistence-unit></persistence>

noms desclasses gérées

Page 34: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

34

R. Grin JPA page 199

Section properties

La section properties dépend du fournisseur de persistanceElle contient les informations pour la connexion mais aussi d’autres informations pour le logging ou la création automatique des tables si elle n’existent pas déjà ; il faut consulter la documentation du fournisseur

R. Grin JPA page 200

Exemple de section properties<properties><property

name="javax.persistence.jdbc.driver"value="oracle.jdbc.OracleDriver"/>

<propertyname="javax.persistence.jdbc.url"value="jdbc:oracle:thin:@...:INFO "/>

<propertyname="javax.persistence.jdbc.user" value="toto"/>

<propertyname="javax.persistence.jdbc.password" value="mdp"/>

</properties>

R. Grin JPA page 201

Source de données

Lorsque JPA est utilisé avec un serveur d’applications, une source de données fournie par le serveur d’applications est le plus souvent utilisée pour obtenir les connexions (voir DataSource dans le cours sur JDBC)On pourra alors trouver :<persistence-unit name="Employe"><jta-data-source>jdbc/EmployeDS</jta-

data-source></persistence-unit name=Employe>

Configuration dynamique (1)

Les informations pour la connexion à la base, en particulier le nom et le mot de passe de connexion à la base, peuvent n’être connues qu’à l’exécution et pas au moment de l’écriture du codeEn ce cas, il est possible de ne donner les informations que lors de la création de la fabrique par la classe Persistence

R. Grin JPA page 202

Configuration dynamique (2)

Il suffit de passer à la méthode createEntityManagerFactory une mapqui contient les propriétés qui écrasent les valeurs contenues dans persistence.xml

R. Grin JPA page 203

Exemple de configuration dynamique// Saisie du nom et du mot de passe. . .// Configuration de la connexionMap props = new HashMap();props.put("javax.persistence.jdbc.user",

nom);props.put("javax.persistence.jdbc.password",

mdp);EntityManagerFactory emf = Persistence.createEntityManagerFactory(

"employes", props);

R. Grin JPA page 204

Page 35: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

35

R. Grin JPA page 205

Les ajouts de EclipseLink

EclipseLink a des extensions par rapport à la norme JPAPar exemple,n loggingn génération automatique de tablesn…

R. Grin JPA page 206

Génération automatique des tablesLa propriété eclipselink.ddl-generationpermet de créer automatiquement les tables au moment de la création de la fabrique de gestionnaires d’entitésCette propriété peut avoir 3 valeurs :n none : aucune création automatiquen create-tables : les tables sont créées si

elles n’existent pas déjàn drop-and-create-tables : si une table

existe déjà, elle est d’abord supprimée avant d’être recréée (utile pour les tests)

R. Grin JPA page 207

Exemple

<properties>. . .<propertyname="eclipselink.ddl-generation" value="drop-and-create-tables"/>

</properties>

Attention, si une fabrique est créée plusieurs fois durant une exécution, les tables seront supprimées à chaque fois !

R. Grin JPA page 208

eclipselink.ddl-generation.output-modeindique ce qui sera fait avec les fichiers DDLValeurs possibles : n sql-script génère les fichiers mais ne

les exécute pasn database exécute les ordres DDL mais

ne génère pas les fichiersn both génère les fichiers et les exécute

(valeur par défaut)

R. Grin JPA page 209

eclipselink.application-locationindique le nom du répertoire qui contiendra les fichiers contenant les ordres DDL de création et de suppression des tables (le répertoire courant par défaut)

R. Grin JPA page 210

eclipselink.create-ddl-jdbc-file-nameindique le nom du fichier qui contiendra les ordres de création des tables ; par défaut, createDDL.jdbc

eclipselink.drop-ddl-jdbc-file-nameidem pour la suppression des tables ; par défaut, dropDDL.jdbc

Page 36: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

36

R. Grin JPA page 211

logging (1)

La propriété eclipselink.logging.levelpeut avoir les valeursn OFF : aucune information

n SEVERE : uniquement les erreurs

n WARNING : les avertissements (et les erreurs)

n INFO (valeur par défaut) : assez peu d’information en plus

n CONFIG : donne des informations au moment du déploiement sur la configuration

R. Grin JPA page 212

logging (2)

n FINE : donne des informations sur les ordres SQL utile pendant les tests et la mise au point

n FINER : encore plus d’informations, par exemple sur les transactions

n FINEST : encore plus d’informations, par exemple sur l’utilisation des séquences

Exemple :<property

name="eclipselink.logging.level" value="FINEST" />

R. Grin JPA page 213

Fichiers XML

R. Grin JPA page 214

Placement des fichiers XML

Par défaut les fichiers XML contenant les méta données sont placées dans le fichier META-INF/orm.xml, sous un répertoire du classpathIl est possible d’indiquer d’autres emplacements avec le tag <mapping-file>dans le fichier persistence.xml qui définit l’unité de persistance

R. Grin JPA page 215

Exemple

<persistence-unit name="xxxx">...<mapping-file>META-INF/queries.xml</mapping-file><mapping-file>META-INF/entities.xml</mapping-file>

</persistence-unit>

R. Grin JPA page 216

Méta-données par défautL’élément <persistence-unit-defaults>contient des valeurs par défaut qui s’appliquent à toutes les entités de l’unité de persistanceLes sous-éléments peuvent être : <schema>(donner le nom du schéma relationnel), <catalog> (idem <schema> pour les SGBD qui supportent les catalogues), <access>(accès pour toutes les classes non annotées), <cascade-persist> (pour imposer la persistance par transitivité) et <entity-listeners> (écouteurs par défaut)

Page 37: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

37

R. Grin JPA page 217

Fichiers XML – annotationsAvantages des annotations :nméta données proches du coden pas besoin de donner le contexte comme

dans les fichiers XMLn plus simple

Inconvénients :n changement des méta données nécessite

une recompilationLes informations données dans les fichiers XML l’emportent sur les annotations

R. Grin JPA page 218

Fichiers XML – annotations

Les annotations sont le plus souvent utiliséesLes fichiers de configuration XML peuvent être préférés lorsque l’information n est dépendante de l’environnement

d’exécution ; par exemple pour les noms de tables ou de colonnes

n concerne plusieurs classes ; par exemple @TableGenerator qui donne le nom de la table qui génère automatiquement les clés d’identification des entités

R. Grin JPA page 219

Exemple de fichier orm.xml (en-tête)

<?xml version="1.0" encoding="UTF-8" ?><entity-mappings xmlns="http://java.sun.com/xml/ns/persistence.orm"xmlns:xsi:"http://www.w3.org/2001/XMLSchema-instance"xsi-schemaLocation ="http://java.sun.com/xml/ns/persistence.xml http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">

R. Grin JPA page 220

Exemple de fichier orm.xml (fin)

<entity class="jpa.Employe"><table name="EMP" /><named-query name="findEmpByName"

<query>select e from Employe e where e.nom like :nomEmploye</query>

</named-query></entity></entity-mappings>

R. Grin JPA page 221

JPA et DAO

R. Grin JPA page 222

Utilité des DAO ?

La possibilité de détacher et rattacher une entité rend souvent les DTO inutiles (voir cours sur DAO et modèles de conception associés)Puisque JPA augmente fortement la portabilité du code chargé de la persistance, est-ce que les DAOs sont encore nécessaires ?

Page 38: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

38

R. Grin JPA page 223

Les DAOs ne sont pas toujours utiles

Pour les petites applications à existence courte, avec peu de fonctionnalités « métier », l’utilisation directe de JPA depuis le code métier (sans utilisation de DAOs) simplifie le code lié à la persistanceLes DAO ne sont alors pas vraiment utiles car JPA offre malgré tout une meilleure portabilité que JDBC et l’utilisation des DAOs rend le code un peu plus complexe

R. Grin JPA page 224

Les DAOs ne sont pas toujours utiles

D’autant plus que code généré automatiquement à partir de la structure d’une base de données par les IDE tels NetBeanspour les applications Web de type « CRUD » utilisent directement JPA et ne comportent pas de DAOsLa tentation est donc grande de ne pas utiliser de DAOs

R. Grin JPA page 225

Les DAOs sont encore utiles

Cependant, pour les applications plus complexes, les DAOs peuvent apporter une meilleure abstraction et une meilleure factorisation du code lié à la persistanceLes détails techniques liés à JPA (ou à une version de JPA) peuvent être cachés dans la couche DAOLes DAOs pourront aussi faciliter le passage éventuel à un autre type de persistance, par exemple à un SGBD objet

R. Grin JPA page 226

Les DAOs sont encore utiles

Evidemment les DAOs sont presque indispensables pour les applications qui utilisent plusieurs types de persistance pour les mêmes données (voir cas d’utilisation donné au début du cours sur les DAOs)Utiliser ou non des DAOs est donc une des premières questions à se poser lorsque l’on développe une application qui accède à une base de données

R. Grin JPA page 227

Exemple de factorisation du code

Un DAO peut contenir des méthodes spécialement adaptées au « métier »Par exemple, une méthode qui renvoie la liste des candidats qui ont obtenu leur examen avec une certaine mention, passée en paramètreCette méthode peut être appelée de plusieurs endroits du code « métier »Le code qui l’utilisera sera plus simple à écrire que s’il utilisait directement JPA

R. Grin JPA page 228

Variantes des DAOs

Parmi toutes les variantes des méthodes des DAOs (voir cours sur les DAOs), celles qui prennent en paramètre ou qui renvoient des objets (des entités JPA dans ce cas) sont le plus souvent choisiesEn effet, les entités détachées peuvent jouer le rôle des DTOs qui sont donc inutiles, et les variantes qui utilisent plusieurs paramètres dont les valeurs correspondent aux propriétés des objets compliquent inutilement le code

Page 39: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

39

R. Grin JPA page 229

DAOs génériques

La généricité permet d’écrire une classe mère générique de tous les DAOs, ce qui allège d’autant les classes filles représentant chacune des classes DAOsLe type des entités gérées et le type de l’identificateur sont les paramètres de type de ce DAO génériqueLes transparents suivants sont un exemple d’implémentation que vous pouvez modifier à votre convenance

R. Grin JPA page 230

Interface DAO générique

public interface DaoGenerique<T,ID extends Serializable> {T findById(ID id);List<T> findAll();void create(T objet);void delete(T entite);T update(T entite);

}T est le type de l’entité

ID est le type de l’identificateur de l’entité

R. Grin JPA page 231

Interface DAO pour une entité

public interface StyloDao extends DaoGenerique<Stylo, Long> { }

On peut ajouter des méthodes adaptée au « métier », comme cette méthode qui renvoie toutes les marques de stylos en vente :public interface StyloDao extends DaoGenerique<Stylo, Long> {List<String> findMarques();

}

R. Grin JPA page 232

Classe DAO générique (1)public abstract class DaoGeneriqueJpa<T, ID extends Serializable> implements DaoGenerique<T, ID> {private Class<T> classeEntite;private EntityManager em;public DaoGeneriqueJpa() {// classe concrète de T passée à findthis.classeEntite = (Class<T>)

((ParameterizedType)getClass()..getGenericSuperclass()).getActualTypeArguments()[0];

}

R. Grin JPA page 233

Classe DAO générique (2)public void insert(T objet) {

em.persist(objet);}public void delete(T objet) {

em.remove(objet);}public T findById(ID id) {

return em.find(classeEntite, id);}public T update(T entite) {

return em.merge(entite);}

R. Grin JPA page 234

Classe DAO générique (3)

public void setEntityManager(EntityManager em) {

this.em = em;}protected EntityManager getEntityManager() {

return this.em;}

}

Page 40: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

40

R. Grin JPA page 235

DAO pour une entité

public class StyloDaoJpaextends DaoGeneriqueJpa<Stylo, Long> implements StyloDao {

public List<Stylo> findAll() {Query query = getEntityManager()

.createNamedQuery("Stylo.findAll");return

(List<Stylo>)query.getResultList();}

}

DAO et multitâche

Un DAO qui utilise JPA contient une instance de EntityManager qui n’est pas « thread-safe » ; il ne faut donc pas le partager entre plusieurs threads

R. Grin JPA page 236

R. Grin JPA page 237

Cache des données

R. Grin JPA page 238

UtilitéTous les fournisseurs de persistance utilisent un cache de second niveau (en plus du contexte de persistance) pour éviter des accès aux bases de données, et donc améliorer les performancesTous les gestionnaires d’entités d’une même unité de persistance utilisent le même cache de second niveauSi une donnée est lue par un gestionnaire et gardée dans le cache, elle pourra être lue par les autres gestionnaires sans accès à la BD

R. Grin JPA page 239

Utilité

La spécification JPA 2 standardise en partie l’utilisation du cache de 2ème niveau ; il faut consulter la documentation du fournisseur de persistance pour connaître les autres possibilités éventuelles

R. Grin JPA page 240

Utilisation des caches

Il n’est pas toujours facile d’utiliser correctement le cache de 2ème niveauLe plus souvent on peut se contenter d’indiquer quelles classes utiliseront ce cachePar exemple, il peut être très intéressant d’utiliser un cache pour des classes dont les données ne changent que très rarement comme les noms des pays

Page 41: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

41

R. Grin JPA page 241

Problèmes éventuels

Parfois ce cache pose des problèmes si la base de données est utilisée en parallèle par d’autres applicationsPar exemple, si des entités liées à une entité sont supprimées de la base en dehors de l’application, le cache peut penser modifier une ligne avec un UPDATE au lieu d’en insérer une nouvelle avec un INSERT, ce qui provoque une erreur

R. Grin JPA page 242

Solutions (1)

L’utilisation de la méthode refresh de EntityManager permet de récupérer dans la base de données des données « fraiches », sans jamais passer par le cacheUn blocage pessimiste peut parfois être la solution si on souhaite interdire la modification de lignes par une autre application (implémentation dépendante du fournisseur de persistance)

R. Grin JPA page 243

Solutions (2)

Parfois la seule solution est de vider le cache ou d’indiquer au fournisseur de ne pas utiliser le cache pour effectuer certaines opérations (la façon de faire dépend en partie du fournisseur de persistance)JPA 2 permet d’effectuer certains réglages pour optimiser l’utilisation du cache, et éviter les problèmes liés aux données qui ne sont pas à jour dans le cache

Utilisation ou non du cacheLe fichier persistence.xml peut indiquer si une unité de persistance utilisera ou non un cache avec l’élément caching qui peut avoir 4 valeurs possibles : ALL, NONE, ENABLE_DELECTIVE et DISABLE_SELECTIVE

Exemple :<caching>ENABLE_SELECTIVE</caching>

Pas de valeur par défaut ; il faut donc toujours donner une valeur pour avoir une application portable entre les fournisseurs de persistance

R. Grin JPA page 244

Utilisation ou non du cache

ALL : un cache sera utilisé pour toutes les entitésNONE : aucun cache ne sera utiliséENABLE_SELECTIVE : par défaut, les entités ne sont pas cachées ; seules le sont celles qui sont annotées par @Cacheable(true)DISABLE_SELECTIVE : par défaut, les entités sont cachées ; seules ne le sont pas celles qui sont annotées par @Cacheable(false)

R. Grin JPA page 245

Annotation @Cacheable

Une classe d’entités peut être annotée pour indiquer si les entités de la classe seront conservées dans le cache (voir élément caching de persistence.xml pour plus de précisions)Exemple :@Entity@Cacheable(true)public class Pays { ... }

R. Grin JPA page 246

@Cacheable suffit cartrue est la valeur par défaut

Page 42: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

42

Interface CacheJPA 2 a introduit cette interface simplifiée avec le cache pour affiner les indications données par @CacheablePar exemple, pour une classe d’entités « cacheable », il est possible d’enlever une certaine entité du cacheSi le cache n’est pas utilisé, les méthodes ne font rien, à part contains qui renvoie toujours falseLe cache s’obtient avec la méthode getCache() de EntityManagerFactory

R. Grin JPA page 247

Méthodes de l’interface Cache

boolean contains(Class cls, Object cléPrimaire) indique si le cache contient une entitévoid evict(Class cls) enlève du cache toutes les entités d’une certaine classevoid evict(Class cls, Object cléPrimaire) enlève du cache une certaine entitévoid evictAll() vide le cache

R. Grin JPA page 248

Propriétés liées au cache

En plus de toutes les possibilités déjà exposées, on peut donner des indications pour les méthodes find, refresh et pour les requêtes (Query) exécutées par un gestionnaire d’entités (voir spécification pour plus de détails)Exemple :em.setProperty(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.USE);

R. Grin JPA page 249

Propriétés pour un find

Il est possible de donner des indications d’utilisation du cache pour un seul findExemple :HashMap props = new HashMap(); props.put(QueryHints.CACHE_RETRIEVE_MODE,

CacheRetrieveMode.BYPASS); em.find(MyEntity.class, id, props);

R. Grin JPA page 250

Propriétés pour les commit

Il est aussi possible d’indiquer si les données validées par un commit seront mises dans le cache

R. Grin JPA page 251 R. Grin JPA page 252

Optimisations

Page 43: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

43

R. Grin JPA page 253

Les performances d’une application peuvent être grandement améliorées parn un choix adapté du mode de récupération

des entités associéesn l’utilisation d’opérations de modifications

en volume, sans création d’entitésn une bonne utilisation du cache de 2ème

niveau

R. Grin JPA page 254

Méthode callback et listener

R. Grin JPA page 255

Méthodes « callback » Des méthodes peuvent être annotées pour indiquer qu’elles seront appelées par le fournisseur de persistance quand une entité passera dans une nouvelle étape de son cycle de vieCes méthodes peuvent appartenir à une classe entité (entity) ou classe mère « mappedSuperclass » ou à une classe « écouteur » (listener)Une méthode peut être annotée par plusieurs de ces annotations

R. Grin JPA page 256

Annotations@PrePersist : quand persist (ou merge) s’est terminé avec succès@PostPersist : après l’insertion dans la BD@PreRemove : quand remove est appelé@PostRemove : après suppression dans la BD@PreUpdate : avant modification dans la BD@PostUpdate : après modification dans la BD@PostLoad : après la lecture des données de la BD pour construire une entité

R. Grin JPA page 257

Callback dans fichier XML

Les méthodes callback peuvent aussi être indiquées dans un fichier XMLUn fichier XML peut aussi indiquer des listeners par défaut qui seront appelées pour toutes les entités, dans le sous-élément <entity-listeners> de l’élément <persistence-unit-defaults>

R. Grin JPA page 258

Exemples d’utilisation

Un trigger de la base de données peut donner les valeurs de l’utilisateur qui a modifié pour la dernière fois une entité, avec la date de cette modificationPour remplacer un tel trigger, il est possible d’ajouter une méthode annotée par @PrePersist qui remplit ces valeurs dans les entitésUne méthode callback peut aussi initialiser des attributs non persistants d’une entité

Page 44: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

44

R. Grin JPA page 259

Callback dans une entité

Ces méthodes ne doivent aucune paramètre et le type retour doit être voidElles ne doivent pas avoir de clause throwsSi elles renvoient une exception non contrôlée, les éventuelles méthodes callbacks suivantes ne sont pas appelées et la transaction est marquée pour un rollback(elle ne pourra pas être validée) Une seule méthode callback d’un certain type (par exemple PrePersist) par entité

R. Grin JPA page 260

Callback dans un écouteur

La signature doit avoir un paramètre compatible avec le type de l’entité gérée pour qu’il puisse contenir l’instance de l’entité« Compatible » signifie que le type doit être un « surtype » de la classe entité : la classe de l’entité, ou une classe mère, ou une interface implémentée par la classe de l’entitéUne classe listener ne doit contenir aucune variable d’instance (elle doit être « sans état ») et doit avoir un constructeur sans paramètre

R. Grin JPA page 261

Attacher un écouteur

L’annotation @EntityListeners permet d’attacher un ou plusieurs écouteurs à une classe entitéExemple :@Entity@EntityListeners({C1.class, C2.class})public class Entite {

R. Grin JPA page 262

Ordre d’appel

Lorsque un événement du cycle de vie survient, les différentes méthodes sont appelées dans cet ordre :

1. Méthodes des listeners par défaut2. Méthodes des listeners3. Méthode de l’entité en cause

R. Grin JPA page 263

Validation des données

Présentation

Dans Java EE 6 la validation des données a été standardisée (JSR 303)La validation des données peut aussi être utilisée dans les applications en dehors de Java EE mais il faut alors ajouter un jar au classpathDes annotations permettent de définir des contraintes sur les données

R. Grin JPA page 264

Page 45: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

45

Exemple

public class Employe {@NotNullprivate int id;@NotNull(message="Le nom doit être donné")@Size(max=40)private String nom;@Pastprivate Date dateEmbauche;...

R. Grin JPA page 265

Validations standard (1/3)

@Null, @NotNullPour toutes les contraintes suivantes, null est considéré comme valide@AssertTrue, @AssertFalse : valeur booléenne imposée (boolean ou Boolean)@Min, @Max : bornes pour un entier (long) ; tous les types de nombres sont supportés, sauf double et float (à cause des erreurs d’arrondi)@DecimalMin, @DecimalMax : bornes pour une valeur décimale (String)

R. Grin JPA page 266

Validations standard (2/3)

@Size avec les attributs min et max ; types supportés : String, Collection, Map, tableau@Digits avec les attributs integer et fraction : nombres maximums de chiffres dans les parties entières et décimales ; types supportés : BigDecimal, String, tous les types entiers (int, Integer, byte,...), y compris BigInteger, mais pas les types double et float (erreurs d’arrondi)

R. Grin JPA page 267

Validations standard (3/3)

@Past, @Future : date avant ou après la date actuelle ; types supportés : Date et Calendar du paquetage java.util@Pattern : la valeur correspond à une expression régulière ; l’attribut flags peut comporter des valeurs utiles pour vérifier la concordance (voir javadoc de java.util.regex.Pattern) : UNIX_LINES, CASE_INSENSITIVE, MULTILINE,...

R. Grin JPA page 268

Validations particulières

Il est possible d’ajouter des validations aux validations standard ; pas étudié dans ce cours

R. Grin JPA page 269

Validation dans JPA

JPA 2 permet de valider les données automatiquement durant le cycle de vie d’une entité, dans les phases « pre-persist », « pre-update » et « pre-remove », ce qui permet d’économiser l’écriture d’un écouteur dont le rôle ne serait que de valider des entités

R. Grin JPA page 270

Page 46: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

46

Configuration

Il est possible de configurer le mode de validation (validation ou non) par l’élément <validation-mode> du fichier persistence.xmlLa valeur par défaut est AUTO : validation si un fournisseur de persistance (jar) est détectéCALLBACK : un fournisseur de persistance doit être présent (sinon une exception est lancée à la création d’une fabrique de EM)NONE : pas de validation

R. Grin JPA page 271

Configuration

Par défaut, les entités sont validées dans les phases pre-persist et pre-update pour le groupe de validation Default (voir API de validation) mais pas pour la phase pre-removeIl est aussi possible de configurer par une propriété passée à la méthode createEntityManagerFactory (par exemple pour valider dans la phase pre-remove)

R. Grin JPA page 272

Exemple d’entité

@Entitypublic class Client {@Id @NotNullprivate int id;@NotNull @Size(max=60)private String nom;@(groups=Remove.class,min=0,max=0)private int nbLivraisonsEnCours;...

}

R. Grin JPA page 273 R. Grin JPA page 274

Adaptation à une base relationnelle préexistante

Position du problème

Parfois les structures des bases préexistantes ne respectent pas les bons usages ou ne correspondent pas aux valeurs par défaut supposées par JPA, pour des raisons diversesC’est souvent le cas pour ce qui concerne la modélisation des associations entre entitésEn ce cas, il faut utiliser les annotations du type @JoinColumn

R. Grin JPA page 275

Un exemple

Les cas sont très divers et ne peuvent être couverts exhaustivementNous allons voir un exemple d’utilisation de l’annotation @JoinColumn qui donne des informations sur une clé étrangère

R. Grin JPA page 276

Page 47: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

47

Un exemple – les tables

Une table Groupe contient les colonnes id (clé primaire de type integer) et nom (de type varchar) ; une table Utilisateur contient les colonnes id (clé primaire de type integer), nom et nom_groupe (toutes les 2 de type varchar)Cette dernière colonne est une clé étrangère vers la colonne nom de la table groupe (qui est une colonne « unique » : 2 groupes ne peuvent avoir le même nom)

R. Grin JPA page 277

Un exemple – les entités

public classe Groupe {@Id private long id;private String nom;@OneToMany(mappedBy="groupe")private Collection<User> users;

}public classe Utilisateur {@Id private long id;private String nom;@ManyToOneprivate Groupe groupe;

}

R. Grin JPA page 278

Un exemple – le problème

Si on laisse JPA générer un schéma relationnel à partir de ces entités, l’association sera traduite par une clé étrangère de type integer qui pointera vers l’id de groupe et une clé étrangère de type varchar qui pointe vers le nom, comme dans la base préexistante

R. Grin JPA page 279

Un exemple – la solution

Il faut compléter l’annotation @ManyToOnede la classe Utilisateur :@ManyToOne@JoinColumn(name="nom_groupe", referencedColumnName="nom")

private Groupe groupe;

JPA peut s’adapter à presque toutes les situations préexistantes ; il faut cependant parfois bien chercher dans la spécification avant de trouver la solution

R. Grin JPA page 280

R. Grin JPA page 281

Précisions pour la génération du schéma de la base de données

R. Grin JPA page 282

Génération du schéma

Tous les fournisseurs de persistance offrent la possibilité de générer automatiquement le schéma de la base de données à partir des classes entités Java (voir section précédente pour le cas où la base existe déjà)En ce cas, il est possible de donner des précisions sur le schéma généré

Page 48: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

48

Contrainte d’unicité sur une colonne

@Column(unique=true)

Une contrainte d’unicité sera ajoutée dans la définition de la colonne de la tableComme dans toute cette section, l’attribut unique ne servira à rien (sinon pour la documentation du code) si le schéma n’est pas généré automatiquement

R. Grin JPA page 283

Contrainte d’unicité sur une table

@Table(uniqueConstraints =@UniqueConstraint(columnNames = {"COL1", "COL2"}))

Une contrainte d’unicité sera ajoutée dans la définition de la table

R. Grin JPA page 284

Contraint NULL

@Column(nullable=false)Une contrainte NOT NULL sera ajoutée à la définition de la colonne

R. Grin JPA page 285

Types de données

@Column(length=25)précise la taille de la colonne de type chaîne de caractères (longueur 255 par défaut, ce qui est souvent beaucoup trop)@Column(precision=10, scale=2)précise la précision (le nombre total de chiffres) et le nombre de chiffres après la virgule pour une colonne de type nombre décimal (float, double,…)

R. Grin JPA page 286

Définition quelconque

On peut même donner la définition du type d’une colonne pour prendre en compte des particularités de certains SGBDL’attribut columnDefinition des annotations @Column, @JoinColumn, @PrimaryKeyJoinColumn, @DiscriminatorColumn permet de définir un type particulierExemple : @Column(columnDefinition="NVARCHAR2(8)")

R. Grin JPA page 287 R. Grin JPA page 288

Bibliographie

Page 49: (Java Persistence API) Langage d’interrogation …deptinfo.unice.fr/~grin/messupports/java/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) Java SE-Paerti 2 Université de Nice - Sophia

49

R. Grin JPA page 289

Sites Web

Spécification officielle de JPA 2 :http://jcp.org/en/jsr/detail?id=317Eclipselink :http://www.eclipse.org/eclipselink/jpa.phpHibernate : http://www.hibernate.org/Open JPA :http://openjpa.apache.org/

R. Grin JPA page 290

Livres

Pro JPA 2: Mastering the Java™ Persistence APIde Mike Keith et Merrick SchincariolEdition Apress(disponible à la BU de Valrose)