Agenda
Historique etproblématique
ORM : Object Relational Mapping
JPA : Java Persistence Api
Entity: Entités
Autres annotations
Contexte de persistance
Opérations prises en charge par le gestionnaire d’entités
Cycle de vie d’une instance d’entité
Obtention d’une fabrique EntityManagerFactory
Création du gestionnaire d’entité EntityManager
Exemple d’insertion d’un livre
Relations entre entités : relations avec cardinalités
Relations entre entités : Héritage
2
Problématique
Problématiques del’accès direct à la BD à l’aide de jdbc :
Pour des raisons de performances, le coût d'ouverture / fermeture d'une
connexion n'est pas négligeable,
Connection con = DriverManager.getConnection(url, "login", "password");
//les ordres SQL
con.close();
L’utilisation du langage SQL rend la couche DAO difficilement
maintenable,
String insertStatement = "Insert into Client(Nom, Prenom,Nature) values
(?, ?, ?)"
Pour pallier à cette problématique et faciliter l’écriture de la couche DAO:
La communauté Java a donc fait naître des Frameworks ORM , tels que
Hibernate, Toplink, EclipseLink
4
6
ORM : ObjectRelational Mapping
Devant le succès des Frameworks ORM,
Sun a décidé de standardiser une couche ORM via une spécification appelée JPA
apparue en même temps que Java 5
7.
JPA : JavaPersistence Api
7
La spécification JPA est un ensemble d’interface du package javax.persistence /
jakarta.persistence
Exemple :
jakarta.persistence.Entity;
jakarta.persistence.EntityManagerFactory;
jakarta.persistence.EntityManager;
jakarta.persistence.EntityTransaction;
9
Les principaux avantagessont les suivants :
JPA peut être utilisé par toutes les applications Java, Java SE ou Java EE.
Mapping O/R (objet-relationnel) avec les tables de la BD, facilitée par les
Annotations.
Un langage de requête objet standard JPQL pour la récupération des objets:
select p from Personne p order by p.nom asc
La description du mapping entre le bean entity et la table peut être fait de
deux façons :
o Utiliser un fichier XML de mapping.
o Utiliser des annotations ;
Dans ce cours, nous allons se focaliser sur L'API JPA avec les annotations
JPA : Java Persistence Api
10.
10
ENTITY: les entités
@Entity
@Table(name= "BOOK")
public class Book {
@Id
@GeneratedValue
private Long id;
@Column(name = "TITLE",nullable = false)
private String title;
private Float price;
@Basic(fetch = FetchType.LAZY)
@Column(length = 2000)
private String description;
private String isbn;
private Integer nbOfPage;
private Boolean illustrations
//Les Getters et les Setters
11.
JPA : Lesentités
Le bean Entity doit respecter les deux règles suivantes :
▪ il doit être annoté par @Entity ;
▪ il doit posséder au moins une propriété déclarer comme clé primaire avec
l'annotation @Id, cette propriété particulière est la clé primaire qui est
l’identifiant unique dans la base de données et aussi dans le POJO.
⮚ Le bean entity est composé de propriétés qui seront mappés sur les champs de
la table de la base de données avec l’annotation @Column ;
Chaque propriété encapsule les données d'un champ d'une table. Ces
propriétés sont utilisables au travers des getter et des setter ;
Composants d'entreprise 11
12.
Mapping entre uneentité et une table
Composants d'entreprise 12
Annotation Rôle
@jakarta.persistence.Table Préciser le nom de la table concernée
par le mapping
@jakarta.persistence.Column Associé à un getter, il permet
d'associer un champ de la table à la
propriété de la classe
@jakarta.persistence.Id Associé à un getter, il permet
d'associer un champ de la table à la
propriété en tant que clé primaire
@jakarta.persistence.GeneratedValue Demander la génération automatique
de la clé primaire au besoin
@jakarta.persistence.Basic Représenter la forme de mapping la
plus simple. Cette annotation est
utilisée par défaut
@jakarta.persistence.Transient Demander de ne pas tenir compte du
champ lors du mapping
13.
L’entité @Tableprécise le nom de la table concernée par le mapping
au niveau de la base de données, elle est utilisée si le nom de la classe est
différent de celui de la table.
Elle possède les attributs suivants :
Composants d'entreprise 13
Attribut Rôle
name Nom de la table
Catalog Catalogue de la table
schema Schéma de la table
uniqueConstraints Contraintes d'unicité sur
une ou plusieurs colonnes
Mapping entre une entité et une table : @Table
14.
L’annotation @Colomnest associée à une propriété d’une entité liée à
un champ de la table au niveau de la base de données
Elle possède les attributs suivants :
Composants d'entreprise 14
Attribut Rôle
name Nom de la colonne
table Nom de la table dans le cas d'un mapping multi-table
unique Indique si la colonne est unique
nullable Indique si la colonne est nullable
insertable Indique si la colonne doit être prise en compte dans les requêtes
de type insert
updatable Indique si la colonne doit être prise en compte dans les requêtes
de type update
columnDefinition Précise le DDL de définition de la colonne
length Indique la taille d'une colonne de type chaîne de caractères
precision Indique la taille d'une colonne de type numérique
scale Indique la précision d'une colonne de type numérique
Mapping entre une entité et une table : @Column
15.
L’annotation @GeneratedValuedemande la génération automatique de la clé
primaire au besoin
Elle possède les attributs suivants :
Le type AUTO est le plus généralement utilisé : il laisse l'implémentation
générer la valeur de la clé primaire ;
Le type IDENTITY utilise un type de colonne spécial de la base de données.
Composants d'entreprise 15
Attribut Rôle
strategy Précise le type de générateur à utiliser : AUTO, SEQUENCE,
IDENTITY ou TABLE. La valeur par défaut est AUTO
generator Nom du générateur à utiliser
Mapping entre une entité et une table : @GeneratedValue
Le typeSEQUENCE utilise un mécanisme nommé séquence proposé par
certaines bases de données notamment celles d'Oracle ;
L'utilisation de cette stratégie nécessite l'utilisation de l'annotation
@jakarta.persistence.SequenceGenerator ;
L'annotation @SequenceGenerator possède plusieurs attributs :
Composants d'entreprise 17
Attribut Rôle
name Nom identifiant le SequenceTableGenerator : il devra être
utilisé comme valeur dans l'attribut generator de l'annotation
@GeneratedValue
sequenceName Nom de la séquence dans la base de données
initialValue Valeur initiale de la séquence
allocationSize Valeur utilisée lors l'incrémentation de la valeur de la
séquence
Mapping entre une entité et une table : @GeneratedValue
18.
Le typeTABLE utilise une table dédiée qui stocke les clés des tables générées.
L'utilisation de cette stratégie nécessite l'utilisation de l'annotation
@jakarta.persistence.TableGenerator ;
L'annotation @TableGenerator possède plusieurs attributs :
Composants d'entreprise 18
Attribut Rôle
name Nom identifiant le TableGenerator : il devra être utilisé comme valeur
dans l'attribut generator de l'annotation @GeneratedValue
table Nom de la table utilisé
catalog Nom du catalogue utilisé
schema Nom du schéma utiliser
pkColumnName Nom de la colonne qui précise la clé primaire à générer
valueColumnName Nom de la colonne qui contient la valeur de la clé primaire générée
pkColumnValue
allocationSize Valeur utilisée lors de l'incrémentation de la valeur de la clé primaire
uniqueConstraints
Mapping entre une entité et une table : @GeneratedValue
Le modèlede base de données relationnelle permet la définition d'une clé
primaire composée de plusieurs colonnes. JPA propose deux façons de gérer
ce cas de figure :
o L'annotation @jakarta.persistence.IdClass
o L'annotation @jakarta.persistence.EmbeddedId
L'annotation @IdClass s'utilise avec une classe qui va encapsuler les propriétés
qui composent la clé primaire. Cette classe doit obligatoirement :
o Être sérialisable ;
o Posséder un constructeur sans argument ;
o Fournir une implémentation dédiée des méthodes equals() et hashCode().
Composants d'entreprise 20
Mapping entre une entité et une table : @GeneratedValue
21.
Composants d'entreprise 21
Exemple: La clé primaire est composée des champs nom et prenom (exemple
théorique qui présume que deux personnes ne peuvent avoir le même nom et
prénom)
Mapping entre une entité et une table : @GeneratedValue
22.
⮚ Il estnécessaire de définir la classe de la clé primaire dans le fichier de
configuration persistence.xml :
Composants d'entreprise 22
Mapping entre une entité et une table : @GeneratedValue
23.
L'annotation @IdClasspossède un seul attribut :
Il faut utiliser l'annotation @IdClass sur la classe de l'entité ;
Il est nécessaire de marquer chacune des propriétés de l'entité qui compose la
clé primaire avec l'annotation @Id ;
Ces propriétés doivent avoir le même nom dans l'entité et dans la classe qui
encapsule la clé primaire ;
Composants d'entreprise 23
Attribut Rôle
Class Classe qui encapsule la clé primaire composée
Mapping entre une entité et une table : @GeneratedValue
Il n'estpas possible de demander la génération automatique d'une clé
primaire composée ;
La classe de la clé primaire est utilisée notamment lors de la recherche ;
Composants d'entreprise 25
Mapping entre une entité et une table : @GeneratedValue
26.
L'annotation @EmbeddedIds'utilise avec l'annotation
@jakarta.persistence.Embeddable
Composants d'entreprise 26
Mapping entre une entité et une table : @GeneratedValue
L'annotation @AttributeOverridesest une collection d'attributs
@AttributeOverride ;
Ces annotations permettent de ne pas avoir à utiliser l'annotation @Column
dans la classe de la clé ou de modifier les attributs de cette annotation dans
l'entité qui la met en œuvre ;
L'annotation @AttributeOverride possède plusieurs attributs :
Composants d'entreprise 28
Attribut Rôle
name Précise le nom de la propriété de la classe imbriquée
column Précise la colonne de la table à associer à la propriété
Mapping entre une entité et une table : @GeneratedValue
29.
Par défaut,toutes les propriétés sont mappées sur la colonne correspondante
dans la table.
L'annotation @jakarta.persistence.Transient permet d'indiquer au
gestionnaire de persistance d'ignorer cette propriété.
Composants d'entreprise 29
Mapping entre une entité et une table : @Transient
30.
L'annotation @jakarta.persistence.Basicreprésente la forme de mapping la
plus simple.
@Basic est optionnelle et est celle utilisée par défault ;
Ce mapping concerne :
o les types primitifs ;
o les wrappers de types primitifs ;
o les tableaux de ces types ;
o les types java.math.BigInteger ;
o java.math.BigDecimal ;
o java.util.Date ;
o java.util.Calendar ;
o java.sql.Date ;
o java.sql.Time et java.sql.Timestamp.
Composants d'entreprise 30
Mapping entre une entité et une table : @Basic
⮚ L'annotation @Basicpossède plusieurs attributs :
Composants d'entreprise 32
Attribut Rôle
fetch Permet de préciser comment la propriété est chargée selon
deux modes :
▪ LAZY : la valeur est chargée uniquement lors de son
utilisation ;
▪ EAGER : la valeur est toujours chargée (valeur par
défaut).
Cette fonctionnalité permet de limiter la quantité de données
obtenues par une requête.
optionnal Indique que la colonne est nullable.
Mapping entre une entité et une table : @Basic
33.
L'annotation @jakarta.persistence.Temporalpermet de fournir des
informations complémentaires sur la façon dont les propriétés encapsulant des
données temporelles (Date et Calendar) ;
La valeur par défaut est timestamp ;
Exemple :
Composants d'entreprise 33
Mapping entre une entité et une table : @Temporal
34.
JPA permetde mapper les champs de types Blob et Clob ;
L'annotation @jakarta.persistence.Lob permet mapper une propriété sur une
colonne de type Blob ou Clob selon le type de la propriété :
o Blob pour les tableaux de byte ou Byte ou les objets sérializables ;
o Clob pour les chaînes de caractères et les tableaux de caractères char ou
Char.
Composants d'entreprise 34
Mapping entre une entité et une table : @Lob
35.
L'annotation @jakarta.persistence.Enumeratedpermet d'associer une
propriété de type énumération à une colonne de la table sous la forme d'un
numérique ou d'une chaîne de caractères ;
Cette forme est précisée en paramètre de l'annotation grâce à l'énumération
EnumType qui peut avoir comme valeur EnumType.ORDINAL (valeur par
défaut) ou EnumType.STRING.
⮚ exemple :
Composants d'entreprise 35
Mapping entre une entité et une table : @Enumerated
36.
L'annotation @jakarta.persistence.SecondaryTablepermet de préciser qu'une
autre table sera utilisée dans le mapping ;
Pour utiliser cette fonctionnalité, la seconde table doit posséder une jointure
entre sa clé primaire et une ou plusieurs colonnes de la première table.
L'annotation @SecondaryTable possède plusieurs attributs :
Composants d'entreprise 36
Attribut Rôle
Name Nom de la table
Catalogue Nom du catalogue
Schema Nom du schéma
pkJoinsColumns Collection des clés primaire de la jointure sous la forme
d'annotations de type @PrimaryKeyJoinColumn
uniqueConstraints
Mapping entre une entité sur plusieurs tables
37.
L'annotation @PrimaryKeyJoinColumnpermet de préciser une colonne qui
compose la clé primaire de la seconde table et entre dans la jointure avec la
première table. Elle possède plusieurs attributs :
Il est nécessaire pour chaque propriété de l'entité qui est mappée sur la
seconde table de renseigner le nom de la table dans l'attribut table de
l'annotation @Column ;
Composants d'entreprise 37
Attribut Rôle
name Nom de la colonne
referencedColumnNa
me
Nom de la colonne dans la première table (obligatoire si
les noms de colonnes sont différents entre les deux
tables)
columnDefinition
Mapping entre une entité sur plusieurs tables:@SecondaryTable
38.
⮚ Exemple :
Composantsd'entreprise 38
Mapping entre une entité sur plusieurs tables:@SecondaryTable
39.
Si lemapping d’une entité utilise plusieurs tables, il faut utiliser l’annotation
@jakarta.persistence.SecondaryTables qui est une collection d’annotation
@SecondaryTables ;
Exemple :
Composants d'entreprise 39
Mapping entre une entité sur plusieurs tables:@SecondaryTable
40.
40
Contexte de persistance
Ensemble des instances d’entités gérées a un instant donné,
gérées par qui ? Le gestionnaire d’entités : EntityManager
Ce contexte peut donc être considéré comme un cache de premier niveau :
c’est un espace réduit ou le gestionnaire stocke les entités avant d’écrire son
contenu dans la base de données,
41.
41
EntityManager: Opérations prisesen charge par le
gestionnaire d’entités
NB : Un flush() est automatiquement effectué au moins à chaque commit
de la transaction en cours,
43
EntityManagerFactory
L’ interface EntityManagerFactorypermet d’obtenir une instance de l’objet
EntityManager, EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa");
« jpa » est le nom de l’unité de persistance, définie dans le fichier de configuration
de la couche JPA METAINF/persistence.xml.
44.
46
Création du gestionnaired’entité EntityManager
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa");
EntityManager em = emf.createEntityManager() ;
48
Fonctionnement de JPA
La Persistence Unit : organise les meta-
données qui définissent le mapping entre
les entités et la base de données dans le
fichier de configuration
METAINF/persistence.xml
La Persistence Manager Factory récupère
ces metas données de la Persistence Unit et
les interprètent pour créer des Persistence
Manager (EntityManager)
Le Persistence Mangager (EntiyManager)
gère les échanges entre le code et la base
de données, c’est à dire le cycle de vie des
entités
Enfin, les opérations du EntityManager est
englobé dans une Transaction.
47.
49
Relations entre entités:Relation un-à-un
@Entity
@Table(name = "jpa03_hb_personne")
public class Personne {
...
@OneToOne(cascade = CascadeType.ALL, fetch=FetchType.LAZY)
/*@OneToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH, CascadeType.REMOVE}, fetch=FetchType.LAZY) */
@JoinColumn(name = "adresse_id", unique = true, nullable = false)
private Adresse adresse;
...
}
@Entity
@Table(name = "jpa03_hb_adresse")
public class Adresse{ ...
/*n’est pas obligatoire*/
@OneToOne(mappedBy = "adresse", fetch=FetchType.EAGER)
private Personne personne;
... }
48.
50
Relations entre entités:Relation objets embarqués
L'annotation
@Embeddable est
utilisée dans le contexte
de JPA (Java
Persistence API) pour
indiquer qu'une classe
peut être "intégrée" dans
une autre entité.
L'annotation
@Embedded est utilisée
pour personnaliser le
mappage d'un ou
plusieurs attributs d'une
classe intégrable
annotée avec
@Embeddable
49.
51
Relations entre entités:Relation un-à-plusieurs et plusieurs-à-un
@Entity
@Table(name="jpa05_hb_article")
public class Article {
...
// relation principale Article (many) -> Category (one) implémentée par une
clé // étrangère (categorie_id) dans Article
// 1 Article a nécessairement 1 Categorie (nullable=false)
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "categorie_id", nullable = false)
private Categorie categorie; ... }
@Entity
@Table(name="jpa05_hb_categorie")
public class Categorie{
...
// relation inverse Categorie (one) -> Article (many) de la relation Article (many)– > Categorie (one)
@OneToMany(mappedBy = "categorie", cascade = { CascadeType.ALL })
private Set<Article> articles = new HashSet<Article>();
...
}
50.
52
@Entity
@Table(name="jpa06_hb_categorie")
public class Categorie{
...
//relation OneToMany non inverse (absence de mappedby) Categorie (one) -> Article (many)
// implémentée par une table de jointure Categorie_Article pour qu'à partir d'une catégorie
// on puisse atteindre plusieurs articles
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Article> articles = new HashSet<Article>();
...
}
Relations entre entités: Relation un-à-plusieurs et plusieurs-à-un
51.
53
Relations entre entités:Relation plusieurs à plusieurs
@Entity @Table(name = "jpa07_hb_personne") public class
Personne { ...
// relation Personne (many) -> Activite (many) via une table de
jointure personne_activite
@ManyToMany(cascade={CascadeType.PERSIST})
@JoinTable(name="jpa07_hb_personne_activite", joinColumns =
@JoinColumn(name = "PERSONNE_ID"), inverseJoinColumns =
@JoinColumn(name = "ACTIVITE_ID"))
private Set<Activite> activites = new HashSet<Activite>();
...
}
@Entity
@Table(name = "jpa07_hb_activite")
public class Activite{
...
// relation inverse Activite -> Personne
@ManyToMany(mappedBy = "activites")
private Set<Personne> personnes = new HashSet<Personne>();
...
}