1 Correspondance Objet - Relationnel Introduction Présupposé 2

Transcription

1 Correspondance Objet - Relationnel Introduction Présupposé 2
Introduction
Ce cours explique les problèmes de base qui se
posent quand on veut faire correspondre
n les données contenues dans un modèle objet
n avec les données contenues dans une base
de données relationnelle
‰ Le cours sur JPA (Java Persistence API)
donnera un exemple concret d’outil qui
automatise en grande partie cette
correspondance
‰
Correspondance
Objet - Relationnel
Université de Nice Sophia-Antipolis
Version 1.0.1 – 15/9/07
Richard Grin
R. Grin
Mapping objet-relationnel
Présupposé
Département
numéro : int
nom : String
lieu : String
La base de données relationnelle manipulée
par une application objet peut déjà exister au
moment de la conception de l’application objet
‰ Le cours qui suit suppose plutôt que la base
n’existe pas
‰ Si ça n’est pas le cas, les adaptations à une
base existante sont le plus souvent pris en
charge par les outils de mapping, au prix
quelquefois d'un mapping un peu plus
complexe
‰
Une association
page 2
Une classe
ajouterEmployé(Employe) : void
1
+contient
Agrégation
+subordonné
Unidirectionnel 0..*
0..*
appartient
Employe
matricule : int
nom : String
poste
:
String
0..1
dateEmbauche : date
salaire : double
+supérieur
hierarchie
Rôle pour
l’association
Participation
fonctionP : String
0..*
0..*
Une classeassociation
Multiplicité
Projet
codeP : String
nomP : String
+participe
ajouterEmploye(Employe)
getSuperieur()
setSuperieur(Employe)
getMatricule()
Héritage
Commercial
commission : double
Directeur
Administratif
setCommission(double)
R. Grin
Mapping objet-relationnel
page 3
R. Grin
Mapping objet-relationnel
page 4
Quelques problèmes du
passage Relationnel ↔ Objet
2 paradigmes
Les paradigmes objet et relationnel sont bien
distincts
‰ Le paradigme objet est plus riche
‰ Dès qu’un modèle objet est complexe (de
l’héritage et beaucoup d’associations) il n’est
pas simple de faire correspondre des objets
et des tables relationnelles
‰
R. Grin
Mapping objet-relationnel
page 5
Identité des objets
Traduction des associations
‰ Traduction de l’héritage
‰ Navigation entre les objets
‰
‰
R. Grin
Mapping objet-relationnel
page 6
1
Problème de base
Plan
Un objet a une structure complexe qui peut
être représentée par un graphe
‰ Le plus souvent ce graphe est un arbre dont la
racine correspond à l’objet et les fils
correspondent aux valeurs des variables
d’instance qui sont persistantes
‰ Il faut « aplatir » ce graphe pour le ranger dans
la base de données relationnelle sous une
forme tabulaire
‰
R. Grin
Mapping objet-relationnel
page 7
1.
2.
3.
4.
5.
Exemple simple de traduction d’une classe
en une table
Identification
Traduction des associations
Traduction de l’héritage
Récupération des objets associés à un objet
R. Grin
Mapping objet-relationnel
page 8
Traduction d’une classe
en une table
Dans les cas les plus simples une classe est
traduite en une table
‰ Chaque objet est conservé dans une ligne de la
table
‰ Exemple : la classe Département est traduite par
la table
DÉPARTEMENT(numéro, nom, lieu)
‰
Exemple simple de
traduction d’une classe
en une table
R. Grin
Mapping objet-relationnel
page 9
R. Grin
Mapping objet-relationnel
page 10
Création de la table en SQL
create table departement (
numero smallint
constraint pk_dept primary key,
nom varchar(15),
lieu varchar(15))
R. Grin
Mapping objet-relationnel
Identification
page 11
R. Grin
Mapping objet-relationnel
page 12
2
Identification dans le monde Objet
Tout objet est identifiable simplement dans
les langages objets (adresse de
l’emplacement mémoire), indépendamment
des données qu’il contient
‰ 2 objets distincts peuvent avoir exactement
les mêmes valeurs pour leurs propriétés
‰
R. Grin
Mapping objet-relationnel
page 13
Identification dans le monde relationnel
Seules les valeurs des colonnes peuvent servir
à identifier une ligne
‰ Si 2 lignes ont les mêmes valeurs, il est
impossible de les différencier
‰ Toute table devrait donc comporter une clé
primaire pour identifier une ligne parmi toutes
les autres lignes de la même table
‰
R. Grin
‰
R. Grin
Mapping objet-relationnel
page 15
page 14
Propriété « clé primaire »
pour les objets
Éviter les identificateurs significatifs
Rappel du cours de L3 : même si les lignes
d’une table peuvent être distinguées par leurs
valeurs, une clé primaire sera souvent rajoutée
pour éviter les identificateurs significatifs
‰ Surtout si la clé significative est composée de
plusieurs propriétés
‰ Les SGBDs peuvent générer automatiquement
des nombres entiers comme clés primaires des
nouvelles lignes insérées (séquences ou
colonnes de type spécial)
Mapping objet-relationnel
Faut-il ajouter aux objets une propriété pour
représenter une clé primaire non significative ?
‰ Le plus souvent la réponse est positive
‰ En effet, elle pourra être utilisée par le code
pour un accès rapide aux données ou par le
code ou l’outil de mapping pour aider à gérer le
mapping objet-relationnel
‰ En ce cas, si le code le permet, on évitera une
méthode « setId » public
‰
R. Grin
Mapping objet-relationnel
page 16
Exemple de duplication
Problème des duplications
Un objet p1 de la classe Produit de code
« s003 » est créé en mémoire à l’occasion
d’une navigation à partir d’une ligne de
facture
‰ On peut retrouver le même produit en
navigant depuis une autre facture, ou en
cherchant tous les produits qui vérifient un
certain critère
‰ Une erreur serait de créer en mémoire
centrale un autre objet p2 indépendant du
premier objet p1 déjà créé
‰
Une même ligne de la base de données ne
doit pas être représentée par plusieurs objets
en mémoire centrale (ou alors le code doit le
savoir et en tenir compte)
‰ Si elle n’est pas gérée, cette situation peut
conduire à des pertes de données
‰
R. Grin
Mapping objet-relationnel
page 17
R. Grin
Mapping objet-relationnel
page 18
3
Pour éviter des duplications
Objets « insérés »
En mémoire, un objet « cache » (nommé
« unité de travail » par Fowler) conserve une
référence vers les objets utilisés
‰ Lors d’une navigation ou d’une recherche dans
la base, le cache intervient :
n Si l’objet est référencé par le cache, celui-ci
le fournit
n Sinon, l’objet est créé avec les données
récupérées dans la base, et ajouté au cache
‰ Cette fonction est remplie par les sessions de
Hibernate et les gestionnaires d’entités de JPA
‰
R. Grin
Mapping objet-relationnel
page 19
Le modèle objet peut avoir une granularité plus
fine que le modèle relationnel
‰ Les instances de certaines classes peuvent
être sauvegardées dans la même table qu’une
autre classe
‰ Ces instances sont appelées des objets
insérés (embedded) et ne nécessitent pas
d’identificateur « clé primaire »
‰
R. Grin
Mapping objet-relationnel
page 20
Exemple
Une classe Adresse peut ne pas avoir de
correspondance sous la forme d’une table
séparée dans le modèle relationnel
‰ Les attributs de la classe Adresse sont
insérées dans la table qui représente la
classe Client
‰ Les objets de la classe Adresse n’ont pas
d’identification liée à la base de données
‰
R. Grin
Mapping objet-relationnel
page 21
Traduction des associations
R. Grin
Dans le code objet une association peut être
représentée par
n une variable d’instance référençant l’objet
associé (association 1:1 ou N:1)
n une variable d’instance de type collection
ou map contenant les objets associés
(association 1:N ou M:N)
n une classe « association » (M:N)
R. Grin
Mapping objet-relationnel
page 22
Exemple pour une
association 1:N (ou N:1)
Les associations en objet
‰
Mapping objet-relationnel
page 23
‰
‰
class Département {
private Collection<Employé> employes;
. . .
}
class Employé {
private Département département;
. . .
}
R. Grin
Mapping objet-relationnel
page 24
4
Exemple pour
une association 1:N
Association en relationnel
‰
Dans le monde relationnel, une association peut
être représentée par
n une ou plusieurs clés étrangères (associations
1:1, N:1 ou 1:N)
n une table association (associations M:N le plus
souvent)
‰
‰
create table DEPT ( . . .)
create table EMPLOYE (
. . .
num_dept integer references DEPT)
Pour faciliter la lecture, la syntaxe est simplifiée pour les contraintes
(pas de nom de contrainte)
R. Grin
Mapping objet-relationnel
page 25
R. Grin
Navigabilité des associations - objet
Dans un modèle objet, une association peut
être bi ou unidirectionnelle
‰ Exemple d’association unidirectionnelle : la
classe Employé a une variable d’instance
donnant son département mais la classe
Département n’a pas de collection
d’employés
‰ En partant d’un département, on n’a alors pas
de moyen simple de retrouver ses employés
Mapping objet-relationnel
page 27
page 26
Navigabilité des associations relationnel
‰
R. Grin
Mapping objet-relationnel
Dans un schéma relationnel, une association
est toujours bidirectionnelle : on peut toujours
« naviguer » vers l’autre bout de l’association
‰ Par exemple, pour trouver les employés du
département 10 :
select matr, nomE from employe
where dept = 10
‰
R. Grin
Mapping objet-relationnel
page 28
Association binaire M:N - Objet
On va d’abord étudier le cas des associations
M:N qui nécessitent une table association
dans le monde relationnel
‰ On étudiera ensuite les autres associations
‰
R. Grin
Mapping objet-relationnel
page 29
2 façons différentes pour représenter une
association M:N :
n une collection ou une map dans chacune
(ou dans une, selon la directionnalité) des
classes associées, qui référence les objets
associés
n une classe association qui représente une
instance de l’association
‰ Si l’association contient des propriétés, seule
la 2ème façon convient
‰
R. Grin
Mapping objet-relationnel
page 30
5
Exemples de classes – solution 1
‰
‰
class Employé {
private Collection<Projet> projets;
. . .
}
class Projet {
private Collection<Employé> employés;
. . .
}
R. Grin
Mapping objet-relationnel
page 31
Solution 1 – variante avec Map
‰
class Projet {
private Map<Integer, Employé> employés;
. . .
}
La clé peut, par exemple, représenter le
matricule d’un employé
‰ La variante avec map permet un accès rapide à
un des employés participant à un projet
‰ La classe Projet reste identique à la première
variante
‰
R. Grin
Exemples de classes – solution 2
‰
‰
‰
class Employé {
Employé ou/et Projet peuvent
. . .
contenir une collection de
}
Participation pour permettre
class Projet {
la navigation
. . .
}
class Participation {
private Employé employé;
private Projet projet;
. . .
}
R. Grin
Mapping objet-relationnel
page 33
Une association M:N est toujours traduite
par une « table/relation association » (pour
la suite on parlera de tables et pas de
relations)
‰ La clé primaire de cette table est le plus
souvent formée des 2 clés des tables qui
représentent les classes qui interviennent
dans l’association
‰
R. Grin
‰
En SQL :
Mapping objet-relationnel
page 34
Classe association (cas M:N)
‰
PARTICIPATION(matr, codeP)
page 32
Association M:N - Relationnel
Exemple de traduction d’une
association binaire M:N
‰
Mapping objet-relationnel
Si l'association a des propriétés, elles sont
ajoutées dans la classe association et dans la
table association
create table participation (
matr integer references emp,
codeP varchar(2) references projet,
primary key(matr, codeP))
R. Grin
Mapping objet-relationnel
page 35
R. Grin
Mapping objet-relationnel
page 36
6
En objet
‰
En relationnel
class Participation {
private Employé employé;
private Projet projet;
private String fonction;
. . .
}
R. Grin
Mapping objet-relationnel
page 37
En SQL :
R. Grin
On peut traduire les associations N:1 ou 1:1 par
une table association, comme pour une
association M:N
‰ Mais le plus simple est d’ajouter la clé de l’autre
classe dans la table qui traduit la classe placée
du côté opposé à la multiplicité 1
‰ La 1ère solution est plus souple mais plus
coûteuse (jointures)
page 39
‰
EMP(matr,…, dept)
‰
En SQL :
Si l'association est représentée par une classe
association (rare), on peut ajouter les attributs
de la classe dans la table qui reçoit la clé de
l'autre classe (ou dans la nouvelle table
association si on a choisi cette solution)
R. Grin
Mapping objet-relationnel
page 38
create table emp (
matr integer primary key,
…
dept smallint references dept)
R. Grin
Classe association (cas N:1 ou 1:1)
‰
Mapping objet-relationnel
Exemple d’une association binaire
N:1 - Relationnel
‰
Mapping objet-relationnel
PARTICIPATION(matr, codeP, fonctionP)
‰
create table participation (
matr integer references emp,
codeP varchar(2) references projet,
fonctionP varchar(15),
primary key(matr, codeP))
Association binaire dont une
multiplicité maximum est 1
(N:1 ou 1:1) - Relationnel
R. Grin
‰
page 41
Mapping objet-relationnel
page 40
Association de degré > 2 - Objet
Une association de degré > 2 peut être
représentée de plusieurs façons différentes
‰ Le plus simple est sans doute de représenter
l’association par une « classe association » qui
contient des références vers les objets qui
participent à l’association
‰ Mais on peut aussi représenter une telle
association par des collections de classes qui
contiennent des collections ou des références
vers des classes qui contiennent des collections
‰
R. Grin
Mapping objet-relationnel
page 42
7
Exemple d’association de degré > 2
Représentation par une classe
Une réservation dans une compagnie
aérienne peut être considérée comme une
association entre les avions, les passagers et
les numéros de siège
‰ En effet, un passager peut occuper plusieurs
sièges (problème de santé par exemple)
‰
R. Grin
R. Grin
‰
Mapping objet-relationnel
page 43
class Reservation {
private Vol vol;
private Passager passager;
private int siège;
. . .
}
‰
class Vol {
private
Collection<Reservation> résas;
. . .
}
class Reservation {
private Passager passager;
private int siège;
. . .
}
R. Grin
Mapping objet-relationnel
page 44
Association de degré > 2
en relationnel
Autre représentation
‰
Mapping objet-relationnel
Dans le monde relationnel on crée une table
pour traduire l’association
‰ La clé primaire de cette table est le plus souvent
formée d'un sous-ensemble des clés des tables
qui traduisent les classes qui interviennent dans
l’association
‰ Le sous-ensemble peut être strict si une
dépendance fonctionnelle existe entre ces clés
‰
page 45
R. Grin
Mapping objet-relationnel
page 46
Gestion des associations
bidirectionnelles
Exemple de traduction d’une
association de degré > 2
Gérer une association est plus complexe dans
le monde objet que dans le monde relationnel,
surtout si elle est bidirectionnelle
‰ Par exemple, si un employé change de
département, il suffit de changer le numéro de
département dans la ligne de l’employé
‰ En objet, il faut en plus enlever l’employé de la
collection des employés du département et le
rajouter dans la collection de son nouveau
département
‰
‰
RESERVATION(nVol, nSiège, codePassager, …)
‰
En SQL :
create table reservation(
nvol varchar(10) references vol,
nsiege integer,
codePassager varchar(10)
references passager,
primary key(nVol, nSiege, codePassager),
...)
R. Grin
Mapping objet-relationnel
page 47
R. Grin
Mapping objet-relationnel
page 48
8
Gestion automatique de
l’ « autre bout » d’une association
Certains framework (EJB 2 par exemple),
automatisent une partie de la gestion des
associations
‰ Ainsi, si le champ « dept » d’un employé est
modifié, l’employé est passé
automatiquement de la collection des
employés du département d’origine dans
celle du nouveau département
‰ D’autres frameworks comme Hibernate ou
EJB 3/JPA préfèrent ne rien automatiser
‰
R. Grin
Mapping objet-relationnel
page 49
Objet dépendant
Un objet dont le cycle de vie dépend du cycle
de vie d’un autre objet auquel il est associé,
appelé objet propriétaire
‰ Aucun autre objet que le propriétaire ne doit
avoir de référence directe vers un objet
dépendant
‰ En ce cas, la suppression de l’objet
propriétaire doit déclencher la suppression
des objets qui en dépendent (déclenchement
« en cascade »)
‰
R. Grin
Mapping objet-relationnel
page 50
Exemple
Une ligne de facture ne peut exister
qu’associée à une (en-tête de) facture
‰ Si on supprime une facture, toutes les lignes
de la facture doivent être supprimées
‰ Tous les outils de mapping, comme JPA,
offrent la possibilité d’automatiser les
suppressions en cascade d’objets
dépendants
‰
R. Grin
Mapping objet-relationnel
page 51
Exemple
‰
‰
Traduction de l’héritage
R. Grin
Classe
abstraite
Pour fixer les idées, et ;-) pour reprendre des
dessins du très bon livre de Martin Fowler
cité dans la bibliographie, on travaillera sur
l’exemple suivant tiré du monde anglophone :
n des sportifs qui peuvent être des
footballeurs ou des joueurs de crickets
n parmi les joueurs de crickets, les joueurs
qui lancent la balle s’appellent les bowlers
Pour en savoir plus sur le cricket :
http://fr.wikipedia.org/wiki/Cricket
R. Grin
Mapping objet-relationnel
page 53
R. Grin
Mapping objet-relationnel
page 52
Exemple
n
Sportifs qui peuvent
être des footballeurs
ou des joueurs de
cricket
n
Les joueurs de
cricket qui lancent la
balle : les bowlers
Mapping objet-relationnel
page 54
9
Plusieurs méthodes de traduction
Représenter toutes les classes d’une
arborescence d’héritage par une seule table
relationnelle
‰ Représenter chaque classe instanciable
(concrète) par une table
‰ Représenter chaque classe, même les classes
abstraites, par une table
‰
R. Grin
Mapping objet-relationnel
page 55
Accessibilité des variables (1)
Cette remarque est valable quelle que soit la
méthode de traduction de l’héritage et pour
d’autre partie de ce cours
‰ Les variables d’instance ne sont pas le plus
souvent accessibles de l’extérieur de la
classe
‰
R. Grin
Mapping objet-relationnel
page 56
Vocabulaire : « polymorphe »
Accessibilité des variables (2)
Association polymorphe : association
représentée par une référence vers une instance
d’une classe ou des classes filles de cette classe
‰ Par exemple, une société garde une référence
vers un sportif (d’un sport quelconque, footballeur
ou joueur de cricket) qu’elle sponsorise
‰ Requête polymorphe : requête qui renvoie une
information conservée dans les instances d’une
classe ou des classes filles de cette classe
‰ Par exemple, requête qui renvoie les noms de
tous les joueurs
‰
Le code qui gère la persistance doit passer
par les accesseurs de ces variables, ou
demander à chaque classe de participer à
cette gestion de la persistance pour ses
propres variables (cela dépend de la façon
dont est effectuée la persistance)
‰ Un moyen souvent utilisé par les outils de
mapping, est la réflexivité Java qui permet
d’outrepasser les restrictions d’accès
accolées aux variables d’instance
‰
R. Grin
Mapping objet-relationnel
page 57
R. Grin
Toutes les classes traduites
par une seule table
Mapping objet-relationnel
page 58
Avantages
Souvent la solution la plus simple à mettre en
place
‰ C’est d’ailleurs la solution la plus
fréquemment choisie
‰ Permet les requêtes et associations
polymorphes
‰
Pour différencier
les types de joueurs
R. Grin
Mapping objet-relationnel
page 59
R. Grin
Mapping objet-relationnel
page 60
10
Une table par classe
Inconvénients
Oblige à avoir de nombreuses colonnes qui
contiennent la valeur NULL
‰ On ne peut déclarer ces colonnes « NOT
NULL », même si cette contrainte est vraie
pour une des sous-classes
‰
Colonne
optionnelle
R. Grin
Mapping objet-relationnel
page 61
R. Grin
Un objet a souvent ses attributs répartis sur
plusieurs tables (celles qui correspondent aux
classes d’une même hiérarchie d’héritage)
‰ Son identité est alors préservée en donnant la
même clé primaire aux lignes qui correspondent
à l’objet dans les différentes tables
‰ Les clés primaires des tables correspondant aux
classes filles sont des clés étrangères vers la clé
primaire de la table correspondant à la classe
mère
‰
Mapping objet-relationnel
page 63
‰
Pour récupérer les informations sur une
instance d’une classe fille, il suffit de faire une
jointure sur ces clés primaires
R. Grin
Pour représenter un bowler
Table Player : (Bill, bowler)
Table Criketer : (Bill, 50)
‰ Table Bowler : (Bill, 48)
‰ En réalité il faudrait utiliser une clé non
significative ; par exemple :
‰ Table Player : (158, Bill, bowler)
‰ Table Criketer : (158, 50)
‰ Table Bowler : (158, 48)
page 64
Simple : bijection entre les classes et les
tables
‰ Permet les requêtes et associations
polymorphes
‰
‰
Mapping objet-relationnel
Mapping objet-relationnel
Avantages
‰
R. Grin
page 62
Préservation de l’identité
Préservation de l’identité
R. Grin
Mapping objet-relationnel
page 65
R. Grin
Mapping objet-relationnel
page 66
11
Une table par classe concrète
Inconvénient
Si la hiérarchie d’héritage est complexe
nécessite de nombreuses jointures pour
reconstituer les informations éparpillées dans
les tables
‰ D’où des instructions complexes, mais surtout
de mauvaises performances
‰ La colonne « type » de la table Players permet
de limiter un peu ce problème ; il est possible,
par exemple, de retrouver les noms des
footballers sans faire de jointure
‰
R. Grin
Mapping objet-relationnel
page 67
R. Grin
C’est la méthode la plus naturelle : une table
par type d’entité
‰ Pas de jointures pour retrouver les
informations
‰
Mapping objet-relationnel
page 69
Ne peut traduire simplement les associations
polymorphes
‰ Par exemple, traduire une classe qui
référence un joueur d’un sport quelconque
(joueur de football ou de cricket)
‰ En effet, aucune table relationnelle ne
correspond à un joueur d’un sport
quelconque et on ne peut donc imposer une
contrainte d’intégrité référentielle (clé
étrangère)
‰
R. Grin
Solution
‰
‰
Mapping objet-relationnel
Mapping objet-relationnel
page 70
Autre problème
Aucune solution vraiment satisfaisante
Des solutions partielles :
n ignorer la contrainte d’intégrité référentielle
n mettre plusieurs colonnes dans la table qui
référence, une pour chaque table concrète
référencée (mais ça sera difficile d’imposer
l’unicité de la référence ; sur l’exemple, ça
sera difficile d’imposer d’avoir une seule
référence vers un joueur)
R. Grin
page 68
Inconvénients (1)
Avantages
R. Grin
Mapping objet-relationnel
page 71
Dans le même ordre d’idée, il est difficile
d’interroger la base pour effectuer une requête
polymorphe
‰ Par exemple, avoir le nom de tous les joueurs
‰
R. Grin
Mapping objet-relationnel
page 72
12
Inconvénients (2)
Solution
On devra lancer plusieurs selects (un pour
chaque sous-classe concrète) et utiliser une
union de ces selects
‰ Le select sera donc plus complexe et sans
doute moins performant
‰
R. Grin
Mapping objet-relationnel
page 73
‰
Pas possible d’assurer simplement l’unicité
des identificateurs pour tous les sportifs (ils
sont répartis sur plusieurs tables distinctes)
R. Grin
Conclusion : une solution à éviter
‰
R. Grin
R. Grin
Mapping objet-relationnel
page 75
page 74
Variantes
Sauf pour des cas bien précis où le
polymorphisme n’est pas important, il vaut
mieux éviter cette solution
‰ D’ailleurs, la version actuelle de la
spécification EJB 3 n’impose pas aux
serveurs d’application d’offrir cette possibilité
de traduction de l’héritage
‰
Mapping objet-relationnel
Dans une arborescence d’héritage ces
stratégies peuvent être mélangées
‰ On peut, par exemple, créer plusieurs tables
pour plusieurs branches de l’arborescence
d’héritage
‰ Mais le risque est de retomber sur les
problèmes de la stratégie « une table par
classe concrète » avec les requêtes et les
associations polymorphes
Mapping objet-relationnel
page 76
Héritage multiple
‰
Dans les cas où l’héritage est traduit par des
tables séparées, l’identifiant dans les classes
descendantes est l’ensemble des identifiants des
classes mères
R. Grin
Mapping objet-relationnel
page 77
Récupération des objets
associés à un objet
R. Grin
Mapping objet-relationnel
page 78
13
Une situation
2 stratégies pour les associations
‰
Lorsqu’un objet est créé à partir des données
récupérées dans la base de données, 2
stratégies vis-à-vis des objets associés à cet
objet :
n récupération immédiate et création des
objets associés
n les objets associés ne sont pas créés tout
de suite, mais seulement lorsque
l’application en a vraiment besoin
R. Grin
Mapping objet-relationnel
page 79
Recherche dans la base de données d’une
facture qui vérifie un certain critère
‰ Un objet de la classe Facture qui correspond
à cette facture est créé
‰ Est-ce que les objets LigneFacture associés
à cette facture doivent aussi être créés ?
‰ Et si la réponse est positive, faut-il créer aussi
les objets Produit correspondants à chaque
ligne de facture ?
‰ Et si la réponse est positive, …
‰
R. Grin
Le risque est de créer un très grand nombre
d’objets, peut-être inutiles
‰ Par exemple, si on veut récupérer cette
facture pour connaître seulement la date de
facturation, on voit que tous ces objets
associés sont totalement inutiles
‰ D’où de mauvaises performances, sans
raisons valables
‰
R. Grin
R. Grin
‰
page 81
La solution est le « lazy loading », mot à mot
« récupération paresseuse », que l’on peut
traduire par « récupération à la demande »
ou « récupération retardée »
Quand un objet est créé à partir des données
enregistrées dans la BD, les objets associés
ne sont pas immédiatement créés
‰ Ils sont remplacés par des objets « proxy » qui
ne contiennent que l’information nécessaire
(clé primaire) pour retrouver les « vrais »
objets associés
‰ Les « vrais » objets ne seront créés par la
suite que si c’est vraiment indispensable
‰
Mapping objet-relationnel
page 83
Mapping objet-relationnel
page 82
Exemple (1)
Récupération « à la demande »
R. Grin
page 80
Récupération « à la demande »
Le problème
Mapping objet-relationnel
Mapping objet-relationnel
Le code recherche la facture de numéro 456
Un objet f de la classe Facture est créé
‰ Les objets correspondants aux lignes de la
facture f sont remplacés par des objets d’une
classe « proxy »
‰ Ces objets « proxy » ne contiennent que la
clé primaire des lignes de la facture dans la
table LIGNE_FACTURE
‰
‰
R. Grin
Mapping objet-relationnel
page 84
14
Exemple (2)
Problème des « N + 1 selects »
Si le programme contient ensuite le code
f.getLigne(i).getQuantite()
‰ L’objet LigneFacture correspondant à la
ième ligne de facture est créé en allant
chercher les informations sur la ligne dans la
base de données
‰ Le message « getQuantite() » lui est
envoyé
‰
R. Grin
R. Grin
‰
Mapping objet-relationnel
page 85
Choisir une bonne stratégie pour récupérer
les données n’est pas facile
‰ En effet, en voulant éviter de récupérer trop
de données on peut tomber sur le problème
des « N + 1 selects »
‰
R. Grin
Mapping objet-relationnel
page 87
page 86
Mauvaise solution
pour les « N + 1 selects »
Un exemple de « N + 1 selects »
Récupérer les 5000 factures éditées après
une certaine date, avec une récupération « à
la demande » des lignes de la facture :
‰ Les 5000 objets « Facture » sont d’abord
récupérées (1 select),
‰ Puis, pour chacune des 5000 factures, les
lignes de facture associées sont récupérées
pour calculer le total (5000 selects)
‰ D’où un total de 5001 selects, alors qu’on
peut obtenir le résultat avec un seul select !
Mapping objet-relationnel
Indiquer que la récupération pour cette
association doit toujours être immédiate
(dans des fichiers de configuration par
exemple) ne convient pas le plus souvent
‰ En effet, dans d’autres circonstances, on ne
souhaitera pas charger les lignes de factures
pour éviter de créer trop d’objets inutiles
‰
R. Grin
Solutions possibles (1)
Mapping objet-relationnel
page 88
Solutions possibles (2)
Lancer un ordre SQL ad hoc qui renvoie
uniquement ce qui est recherché
‰ Exemple : pour trouver la facture qui a le plus
gros total, inutile de charger toutes les
factures et lignes de factures en mémoire
‰ Le plus simple, mais ne convient pas si on
veut des informations plus complexes sur les
objets associés
‰ Il faut cependant retenir que, lorsque c’est
possible, c’est souvent la meilleure solution
pour éviter la création de nombreux objets
‰
R. Grin
Mapping objet-relationnel
page 89
Permettre de spécifier une stratégie spéciale
pour une requête particulière
‰ On peut alors indiquer que le mode de
récupération ne sera pas immédiat par
défaut, mais que ce mode devra être
immédiat pour une requête particulière
‰ Tous les outils de mapping le permettent
‰
R. Grin
Mapping objet-relationnel
page 90
15
Code avec Hibernate
Code avec JPA
String texteQuery =
"select f from Facture f "
+ " join fetch f.lignes "
+ " where f.date > '1/1/06'";
Query query = em.createQuery(texteQuery);
List<Facture> liste =
(List<Facture>)query.getResultList();
System.out.println(liste.get(0).getLigne(0));
Ne générera aucune
requête SQL
R. Grin
Mapping objet-relationnel
page 91
List results = session.createCriteria(Item.class)
.add( Expression.eq("item.seller", user) )
.setFetchMode("bids", FetchMode.EAGER).list();
// évite duplication de résultats (due au outer join)
Iterator items = new HashSet(results).iterator();
List maxAmounts = new ArrayList();
while (items.hasNext()) {
Item item = (Item) items.next();
BigDecimal max = new BigDecimal("0");
Iterator b = item.getBids().iterator();
while (b.hasNext()) {
Bid bid = (Bid) b.next();
if ( bid.getAmount().compareTo(max) == 1 )
max = bid.getAmount();
}
maxAmounts.add(new MaxAmount(item.getId(), max));
}
R. Grin
Conclusion de cette partie du cours
‰
R. Grin
R. Grin
Mapping objet-relationnel
page 93
page 92
Bibliographie
La correspondance entre le modèle objet et le
modèle relationnel n’est pas une tâche facile
‰ Les outils et framework ORM (étudiés à la fin
de ce cours) réduisent grandement le code qui
permet cette correspondance et facilitent donc
les adaptations mutuelles des 2 modèles
‰
Mapping objet-relationnel
Patterns of Enterprise Application
Architecture, de Martin Fowler, Addison
Wesley
Mapping objet-relationnel
page 94
16