Documente Academic
Documente Profesional
Documente Cultură
JPA
Présentation de JPA
pour Java EE
Compléments sur les entités : identité,
associations, héritage
Langage d’interrogation
JPA
Spécification pour la persistance des objets Java
dans une base de données (BD) relationnelle
ORM, Object-Relational mapping, fait
Présentation de JPA correspondre le monde relationnel et le monde
des objets
Au-dessus de JDBC
Utilisable avec Java EE ou avec Java SE
1
Entité Exemple d’entité – identificateur
et attributs
Classe dont les instances peuvent être
persistantes @Entity
Annotée par @Entity public class Departement { Clé primaire
dans la base –
« entité » peut aussi désigner une instance de @Id
@GeneratedValue obligatoire
classe entité
private int id; générée
automatiquement
private String nom;
private String lieu;
2
Définition d’une source de données Exemple
Directement dans le serveur d’application @DataSourceDefinition(
Dans l’application,
name = "java:app/jdbc/b1",
className =
de façon standard par
"org.apache.derby.jdbc.ClientDataSource",
@DataSourceDefinition (voir TP 3)
portNumber = 1527,
d’une façon particulière au serveur serverName = "localhost",
d’application (glassfish-resources.xml par user = "APP", password = "APP",
exemple) databaseName = "db1")
@Stateless
public class MonEJB { ... }
…
Exemple 1 Exemple 2
nom dans persistence.xml public void augmenter(String poste, int prime) {
@Stateless String requete = Que fait cette méthode ?
public class DepartementFacade { "SELECT e FROM Employe e "
@PersistenceContext(unitName = "employes") + " WHERE e.poste = :poste";
private EntityManager em; EM injecté par le container Query q = em.createQuery(requete);
q.setParameter("poste", poste);
public void create(Dept dept) { List<Employe> liste = q.getResultList();
em.persist(dept); for (Employe e : liste) {
dept.setLieu("Paris"); enregistré dans la BD ? e.setSalaire(e.getSalaire() + prime);
}
} Oui Est-ce que les augmentations
}
... seront dans la base de données ?
}
Transaction démarrée
au début de la méthode Pourquoi ? Oui, car les employés récupérés dans la BD
et fermée à la fin sont ajoutés par em au contexte de persistance
R. Grin JPA page 17 R. Grin JPA page 18
3
Conditions pour une classe entité
Constructeur sans paramètre protected ou
public
Attribut qui représente la clé primaire dans la BD
Entités
Pas final
Méthodes ou champs persistants pas final
4
Types persistants Types « basic »
Un attribut persistant peut être d’un des types Types primitifs (int, double,…) ou
suivants : enveloppes de type primitifs (Integer,…)
« basic » String, BigInteger, BigDecimal
« Embeddable » Date, Calendar, Time, Timestamp
collection d’éléments de type « basic » ou Énumérations
Embeddable Tableaux de byte, Byte, char, Character
Plus généralement Serializable
(sauvegardé comme un tout dans la base)
gérée par un EM (méthode persist, ou noms des colonnes = noms des attributs
instance récupérée dans la BD par une Par exemple, la classe Departement
requête) correspond à la table Departement avec les
détachée : a une identité dans la BD mais colonnes id, nom, lieu
n’est plus gérée par un EM Convention plutôt que configuration pour JPA
supprimée : gérée par un EM ; données
supprimées dans la BD au commit
(méthode remove)
R. Grin JPA page 27 R. Grin JPA page 28
5
Exemple
@Embeddable
public class Adresse {
private int numero;
Gestionnaire d’entités
private String rue;
private String ville;
(Entity Manager)
. . .
}
@Entity
public class Employe {
@Embedded optionnel
private Adresse adresse;
...
}
R. Grin JPA page 31 R. Grin JPA page 32
6
Propagation de contexte EM étendu
Avec un EM de portée transaction, à chaque @Stateful
opération JPA, l’EM regarde si un CP est déjà public class Caddy {
attaché à la transaction @PersistenceContext(type=EXTENDED)
EntityManager em;
Si c’est le cas, ce CP est utilisé par l’EM, sinon Même CP conservé
le container en crée un nouveau et l’attache à ...
pendant plusieurs transactions
la transaction }
Permet à plusieurs EMs d’utiliser le même CP Permet d’établir une conversation longue
pendant une transaction entière entre l’utilisateur et la BD, sans avoir à gérer
des entités détachées (le contexte reste
ouvert entre les transactions)
R. Grin JPA page 37 R. Grin JPA page 38
7
refresh(entité) Contexte de persistance - cache
Données de la BD sont copiées dans l’entité Un CP est un cache pour les accès à la BD
Pour avoir la dernière version de l’entité find ou query ramènent les données du
cache
Bénéfice : meilleures performances
Attention, les données du cache ne tiennent
pas compte des modifications effectuées
sans passer par l’EM
Peut poser des problèmes ; un refresh peut
être la solution
Pour que ces modifications soient données de a il faut écrire ce type de code :
enregistrées dans la BD, il est nécessaire de a = em.merge(a);
rattacher l’entité à un EM par la méthode
merge
8
Clé primaire
L’attribut, annoté @Id correspond à la clé
primaire dans la table associée
Ne jamais le modifier dès que l’entité
@IdClass
9
Faire TP 3
Associations
10
Exemple Valeurs par défaut
Dans la classe Employe : Si une valeur par défaut ne convient pas,
@ManyToOne ajouter une annotation dans le bout
private Departement departement; propriétaire
Dans la classe Departement : Par exemple, pour indiquer le nom de la
@OneToMany(mappedBy = "departement") colonne clé étrangère :
private Collection<Employe> employes;
@ManyToOne
Quel est le bout propriétaire ? Classe Employe @JoinColumn(name="DEPT")
private Departement departement;
Dans quelle table sera la clé étrangère ? Table EMPLOYE
plus simple)
un attribut identificateur par classe
participant à l’association
R. Grin JPA page 65 R. Grin JPA page 66
11
Code classe association (début) Code classe association (fin)
public Participation() { }
@Entity
public class Participation {
public Participation(Employe employe,
@Id @GeneratedValue
Projet projet, String fonction) {
private int id;
this.employe = employe;
@ManyToOne
private Employe employe; this.projet = projet;
@ManyToOne this.fonction = fonction;
private Projet projet; }
private String fonction; // Accesseurs pour employe et projet
...
12
EAGER ou LAZY Récupération tardive
JPA laisse le choix de récupérer ou non
Supposons une association en mode lazy
immédiatement les entités associées
entre un département et ses employés
Mode EAGER : les données associées sont
On récupère un département
récupérées immédiatement
Plus tard on veut avoir le nom d’un employé
Mode LAZY : les données associées ne sont
Cet employé est alors récupéré par l’EM si
récupérées que lorsque c’est vraiment
nécessaire (lazy loading) l’entité département n’est pas alors détachée
(automatique, on n’a rien à faire)
Et si le département est détaché ?
Il faut faire un merge préalable du département
Stratégies
2 stratégies pour la traduction de l’héritage :
une seule table pour une hiérarchie
d’héritage (SINGLE_TABLE) ; par défaut
Héritage une table par classe ; les tables sont jointes
pour reconstituer les données (JOINED)
La stratégie « une table distincte par classe
concrète » est optionnelle
(TABLE_PER_CLASS)
13
Toutes les classes traduites Exemple « 1 table par hiérarchie »
par une seule table Dans la classe
@Entity racine de la
@Inheritance(strategy = hiérarchie ;
InheritanceType.SINGLE_TABLE) optionnel
public abstract class Personne {...}
Clé étrangère
et primaire
Exemple
@Entity
@Inheritance(strategy =
Requêtes – JPQL
InheritanceType.JOINED)
public abstract class Personne {...}
@Entity
Java Persistence Query Language
@DiscriminatorValue("E")
public class Employe extends Personne {
...
}
14
IMPORTANT Chercher par identité
Cette section concerne les entités retrouvées find retrouve une entité en donnant son
en interrogeant la base de données identificateur dans la BD :
Departement dept =
Toutes ces entités sont automatiquement em.find(Departement.class, 10);
gérées par le gestionnaire d’entités
Les modifications apportées à ces entités
seront enregistrées au prochain commit
cast obligatoire
R. Grin JPA page 87 R. Grin JPA page 88
15
Exemples de requêtes Obtenir le résultat de la requête
Alias de classe obligatoire
select e from Employe e Résultat = une seule valeur ou entité :
select e.nom, e.salaire from Employe e Object getSingleResult()
select e from Employe e Résultat = plusieurs valeurs ou entités :
where e.departement.nom = 'Direction' List getResultList()
select d.nom, avg(e.salaire)
from Departement d join d.employes e
group by d.nom
having count(d.nom) > 5
16
Exemples de paramètres Clauses d’un select
Query query = em.createQuery( select
"select e from Employe as e " JPQL permet les sous-requêtes
+ "where e.nom = ?1");
from
et même les sous-requêtes
query.setParameter(1, "Dupond"); where
synchronisées
Query query = em.createQuery( group by
"select e from Employe as e "
having
+ "where e.nom = :nom");
query.setParameter("nom", "Dupond"); order by
Contre-exemple Jointure
« d.employes.nom » est interdit car Interne (jointure standard join)
d.employes est une collection
Externe (left outer join)
Pour avoir les noms des employés d’un
Avec récupération de données en mémoire
département, il faut une jointure : (join fetch) ; pour éviter le problème des
select e.nom
from Departement d « N +1 selects »
join d.employes e
where d.nom = 'Direction'
17
join fetch Fonctions
Évite le problème des « N + 1 selects » Pour les chaînes de caractères : concat,
select e substring, trim, lower, upper, length,
from Employe as e locate
join fetch e.participations Arithmétique : abs, sqrt, mod, size
Les participations sont créées en même temps Temporelles : current_date,
que les employés (mais pas retournées par le current_time, current_timestamp
select)
Fonctions de regroupement : count, max, min,
L’instruction avg
employe.getParticipations()
case (semblable CASE de SQL)
ne nécessitera pas d’accès à la base
API « criteria »
Tout ce qui peut être fait avec JPQL peut l’être
avec cette API
Les requêtes JPQL sont des String qui
peuvent contenir des erreurs (par exemple le Opération de modification
nom d’une classe qui n’existe pas) en volume
L’avantage de l’API « critères » est que les
requêtes peuvent être vérifiées à la compilation
L’inconvénient est que le code est un peu plus
complexe à écrire, et sans doute moins lisible
Utilité Exemple
String ordre =
Augmenter les 10 000 employés de 5% "update Employe e " +
Une solution : " set e.salaire = e.salaire * 1.05";
Query q = em.createQuery(ordre);
1. Créer toutes les entités « Employe » en
int nbEntitesModif = q.executeUpdate();
lisant les données dans la base
2. Modifier le salaire de chaque entité
18
Gestion de la concurrence
Par défaut, les problèmes d’accès concurrents
sont gérés avec une stratégie optimiste :
on pense qu’aucune autre transaction ne
19