27/02/22 © Robert Godin. Tous droits réservés. 1
16 Base de
données objet
Introduction
Persistance transparente dans un langage objet
Pas de défaut d’impédance
–
pas de transformation entre modèles
Navigation rapide vs jointure
–
stockage en grappe
–
accès par pointeur
Quelques niches
–
ingénierie, télécom, applications scientifiques, Web 2, …
–
graphe d’objets complexe
–
temps réel
–
BD enchâssée
Norme ODMG
Portail : http://www.odbms.org/
27/02/22 © Robert Godin. Tous droits réservés. 3
16.1 Le langage de définition de données ODL
Basé sur IDL (CORBA/OMG)
Non supporté
– association n-aire n>2
– classe associative
Types littéraux (valeurs)/objets
Exemple UML
Personne nom : String
prénom : String
setNomPrénom(n : String, p : String)
Mem bre
téléphoneRésidence : String
$ nbMaxPrêts : Integer = 5
$ duréeMaxPrêts : Integer = 7 nbRetards() : Integer
PrêtEnCours retour(date : Date) PrêtArchivé
dateRetour : Date
{dateRetour >= datePrêt}
{statut = "prêté" ssi PrêtEn Cours de l'Exemplaire est non vide}
{Le nombre de PrêtEnCours d'un Membre <= nbMaxPrêts}
Employé {UNIQUE : codeMatricule}
codeMatricule : String
catégorieEmployé : enum(bibliothécaire, commis) catégorieUtilisateur
Catégorie {UNIQUE: code}
code : String descripteur : String
0..1
* parent 0..1
enfant
* Auteur
Editeur {UNIQUE: nomEditeur}
nomEditeur : String ville : String
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée nbExemplairesDisponibles() : Integer
1 ** 1 1..*
1..* 1..*
1..*
1
1..*
1
1..*
Exemplaire {UNIQUE: idExem plaire}
idExem plaire : String dateAchat : Date
statut : enum(prêté, disponible, retiré) 1..*
1
1..*
1 Prêt datePrêt : Date
getEm prunteur() : Utilisateur getExemplaire() : Exem plaire
1
*
1
* Utilisateur
{UNIQUE :idUtilisateur}
idUtilisateur : String motPasse : String setMotPasse(m : String) nbPrêtsEnCours() : Integer
*
1 *
1
{ordonné}
{Il ne peut y avoir plus d'un PrêtEnCours pour un même Exemplaire}
{disjointe, complète}
{disjointe, complète}
{chevauchante, complète}
TypeDonnéesAnnée {Integer > 0 }
<<datatype>>
27/02/22 © Robert Godin. Tous droits réservés. 5
16.1.1 Classe et interface ODL
Class Livre
( extent livres
key ISBN)
{ attribute string ISBN;
attribute string titre;
attribute integer annéeParution;
relationship set<Exemplaire> lesExemplaires inverse Exemplaire::leLivre
relationship list<Auteur> lesAuteurs inverse Auteur::lesLivres
integer nbExemplairesDisponibles();
};
Interface Personne
{ attribute string nom;
attribute string prénom;
void setNomPrénom(in string n; in string p);
};
16.1.1.1 INTERFACE ODL
Pas d ’extent (non instantiable)
Attribut/association
– équivalent lecteur/modifieur
– non hérité par interface
27/02/22 © Robert Godin. Tous droits réservés. 7
16.1.2 Héritage d'interface (:) et de classe (extends)
Class Utilisateur : Personne ( extent utilisateurs
key idUtilisateur) { attribute string nom;
attribute string prénom;
attribute string idUtilisateur;
attribute string motPasse;
relationship set<Prêt> lesPrêts inverse Prêt::lUtilisateur void setMotPasse(in String m);
integer nbPrêtsEnCours();
};
Class Employé extends Utilisateur ( extent employés
key codeMatricule)
{ attribute string codeMatricule;
attribute enum CatEmp{bibliothécaire, commis}catégorieEmployé;
};
16.1.3 Littéral ODL
Literal_type
Atomic_literal Collection_literal Structured_literal
long long long short
unsigned long unsigned short
float double
boolean
octet char
string
T set
T bag
T list
T array
K, T dictionary
date
time
timestamp
interval
listeAttributs struct
liste Valeurs
27/02/22 © Robert Godin. Tous droits réservés. 9
Littéral structuré
Class Membre
( extent membre key noMembre)
{ struct typeDonnéesAdresse{
integer noCivique;
integer numéroAppartement;
string nomRue;
string nomVille;
string nomProvince;
string nomPays;
string codePostal;
};attribute integer noMembre;
attribute string nom;
attribute string prénom;
attribute adresse typeDonnéesAdresse;
};
Membre {UNIQUE : noMembre}
noMembre : Integer nom : String
prénom : String
adresse : typeDonnéesAdresse
typeDonnéesAdresse numéroCivique : Integer
numéroAppartement : Integer nomRue : String
nomVille : String nomProvince : String nomPays : String codePostal : String
<<datatype>>
16.1.4 Collections ODL
Class Livre
( extent livres
key ISBN)
{ …
attribut set<Exemplaire> lesExemplaires
… };
Class Exemplaire
( extent exemplaires key idExemplaire) {
… attribut Livre leLivre
…
};
27/02/22 © Robert Godin. Tous droits réservés. 11
16.1.5 Association en ODL (relationship)
Class Livre
( extent livres
key ISBN)
{ …
relationship set<Exemplaire> lesExemplaires inverse Exemplaire::leLivre
… };
Class Exemplaire
( extent exemplaires key idExemplaire)
{ …
relationship Livre leLivre
inverse Livre::lesExemplaires
…
};
16.1.6 Spécification de la signature des opérations
Class Utilisateur : Personne ( extent utilisateurs
key idUtilisateur) { attribute string nom;
attribute string prénom;
attribute string idUtilisateur;
attribute string motPasse;
relationship set<Prêt> lesPrêts
inverse Prêt::lUtilisateur void setMotPasse( in String m);
integer nbPrêtsEnCours();
};
27/02/22 © Robert Godin. Tous droits réservés. 13
16.2 Objets
transients/persistants
Cohabitation des objets
transiants/persistants pour une même classe
Persistance par atteignabilité (par
référence)
16.2.1 Constructeurs d'objets
Interface ObjectFactory { Object new();
};
Interface Object
{ enum Lock_Type{read, write, upgrade};
void lock(in Lock_Type mode) raises(LockNotGranted);
boolean try_lock(in Lock_Type mode);
boolean same_as(in Object anObject);
Object copy();
void delete();
};
27/02/22 © Robert Godin. Tous droits réservés. 15
16.2.2 Contrôle de concurrence
Pessimiste par défaut
– verrouillage en deux phases
– mode read (partagé) en lecture
– mode write (exclusif) en écriture
– mode upgrade
demande explicite par lock() ou try-lock()
16.2.3 Noms de racines persistantes
bind() pour créer un nom de racine persistante
–
extent est une racine persistante
persistance par atteignabilité (reachability)
–
objets qui sont référencés par une racine deviennent persistants
–
au commit
lookup() pour chercher la racine
Interface Database{ void open(in String anOdmsName)
raises(DatabaseNotFound,DatabaseOpen);
void close() raises(DatabaseClosed, TransactionInProgress);
void bind(in Object anObject, in String aName) raises(DatabaseClosed, ObjectNameNotUnique, TransactionNotInProgress);
Object unbind(in String aName)
raises(DatabaseClosed, ObjectNameNotFound, TransactionNotInProgress);
Object lookup(in String aName)
raises(DatabaseClosed, ObjectNameNotFound, TransactionNotInProgress);
ODLMetaObjects::Module schema()
raises(DatabaseClosed, TransactionInProgress) ;
27/02/22 © Robert Godin. Tous droits réservés. 17
Autres approches de contrôle de la persistance
Contrôle programmatique explicite
– objet.makePersistent()
Par héritage
– sous-classes d ’une classe spéciale
16.2.4 Gestion des OID persistants
Table OID -> adresse transiante
– coût important de traduction
Mutation de pointeurs (pointer swizzling)
– bit qui distingue entre OID et adresse transiante
– quand muter ?
Automatique : au chargement
À la demande : au premier parcours
Mécanisme de mémoire virtuelle (hardware)
–
Object Store
27/02/22 © Robert Godin. Tous droits réservés. 19
16.3 Le langage de requête OQL
Similarités avec SQL
– table -> racine persistente
Grammaire complète :
– http://www.odmg.org
16.3.1 SELECT de base
Le titre des livres parus après 1999
SELECT l.titre FROM livres AS l
WHERE l.annéeParution > 1999 type du résultat :
litteral bag<String>
Class Livre
( extent livres key ISBN)
{ attribute string ISBN;
attribute string titre;
attribute integer annéeParution;
relationship set<Exemplaire> lesExemplaires inverse Exemplaire::leLivre;
relationship list<Auteur> lesAuteurs inverse Auteur::lesLivres;
relationship Editeur lEditeur
inverse Editeur::lesLivres;
relationship Catégorie laCatégorie inverse Catégorie::lesLivres;
integer nbExemplairesDisponibles();
};
27/02/22 © Robert Godin. Tous droits réservés. 21
16.3.2 Clause DISTINCT
Le titre et l'année des livres parus après 1999 sans doublons
SELECT DISTINCT l.titre, l.annéeParution FROM livres l
WHERE l.annéeParution > 1999 type du résultat :
litteral set<struct<titre:String,annéeParution integer>>
16.3.3 Constructeur STRUCT
Le titre et l'annéeParution des livres parus après 1999
Équivalent à
SELECT STRUCT(titre:l.titre, annéeParution:l.annéeParution) FROM livres AS l
WHERE l.annéeParution > 1999 type du résultat :
litteral bag<struct<titre:String,annéeParution:integer>>
SELECT l.titre,l.annéeParution FROM livres AS l
WHERE l.annéeParution > 1999 type du résultat :
litteral bag<struct<titre:String,annéeParution:integer>>
27/02/22 © Robert Godin. Tous droits réservés. 23
16.3.4 Sélection d'objets de la BD
Collection de références aux objets de la classe Livre parus après 1999
Peut ensuite manipuler les objets persistants
SELECT l
FROM livres l
WHERE l.annéeParution > 1999 type du résultat :
litteral bag<Livres>
16.3.5 Requête sans SELECT
Collection des livres
livres
type du résultat :
set<Livres>
27/02/22 © Robert Godin. Tous droits réservés. 25
16.3.6 Expressions de chemins
Le titre de l ’objet unLivre (type Livre)
Exemple avec une opération
unLivre.titre
type du résultat : String
unLivre.nbExemplaires() type du résultat :
litteral integer
Expressions de chemins (suite)
Naviguer une association
En cascade
unLivre.lesExemplaires type du résultat :
set<Exemplaire>
unLivre.laCatégorie.leParent type du résultat :
Catégorie
27/02/22 © Robert Godin. Tous droits réservés. 27
Navigation à travers une collection
Les idExemplaires d'un livre
Les idExemplaire des livres de l'année 2000
SELECT e.idExemplaire
FROM unLivre.lesExemplaires AS e type du résultat :
litteral bag<String>
SELECT e.idExemplaire
FROM livres AS l, l.lesExemplaires AS e WHERE l.annéeParution = 2000
type du résultat :
litteral bag<String>
Navigation à travers une collection (suite)
Le ISBN des livres actuellement empruntés par le membre dont le idUtilisateur = ‘unId’
SELECT p.lExemplaire.leLivre.ISBN
FROM membres AS m, m.lesPrêts AS p WHERE m.idUtilisateur = "unID" AND
P IN prêtsEnCours type du résultat :
litteral bag<String>
27/02/22 © Robert Godin. Tous droits réservés. 29
16.3.7 SELECT enchâssé dans le FROM
les idExemplaire des livres de l'an 2000
SELECT e.idExemplaire
FROM (SELECT l.lesExemplaires FROM livres AS l
WHERE l.annéeParution = 2000) AS l2k, l2k.lesExemplaires AS e
type du résultat :
litteral bag<String>
16.3.8 SELECT enchâssé dans la
spécification du résultat d'un SELECT
Les ISBN des livres de l'an 2000
accompagnés de leurs exemplaires empruntés
SELECT
STRUCT(ISBN: l.ISBN, emprunts:(SELECT e
FROM l.lesExemplaires AS e WHERE e.statut = "prêté")) FROM livres AS l
WHERE l.annéeParution = 2000 type du résultat :
litteral bag<STRUCT<ISBN:String,emprunts:set<Exemplaire>>
27/02/22 © Robert Godin. Tous droits réservés. 31
16.3.9 Aplatissement d'une collection de collections (FLATTEN)
FLATTEN(set ( set(1, 3), set (2, 5, 3), set (5, 8)) ) = set(1, 2, 3, 5, 8)
Extraire les exemplaires des livres parus en l'an 2000
FLATTEN (SELECT l.lesExemplaires FROM livres AS l
WHERE l.annéeParution = 2000) type du résultat :
litteral bag<Exemplaire>
16.3.10 Extraction de l'élément d'un singleton (ELEMENT)
Retourner l’objet de la classe
Livre qui correspond au ISBN =
‘111-11111-11’
element(
SELECT l FROM livres AS l
WHERE l.ISBN = "111-11111-11"
)
27/02/22 © Robert Godin. Tous droits réservés. 33
16.3.11 Constructeurs d'objets
Le constructeur suivant construit un objet de la classe Exemplaire
Class Exemplaire
( extent exemplaires key idExemplaire)
{ attribute string idExemplaire;
attribute date dateAchat;
attribute enum statut {prêté,disponible,retiré};
relationship Livre leLivre
inverse Livre::lesExemplaires relationship set<Prêt> lesPrêts
inverse Prêt::lExemplaire };
Exemplaire(
idExemplaire : "A1E2F",
dateAchat : date "2000-04-25", statut : "disponible",
leLivre : element(
SELECT l FROM livres AS l
WHERE l.ISBN = "111-11111-11"),
LesPrêts : set())
16.3.12 Comparaison par identité ou par valeur
Le = compare les OID des objets
27/02/22 © Robert Godin. Tous droits réservés. 35
16.3.13 Quantificateurs FOR ALL et EXISTS
Les livres dont tous les exemplaires sont empruntés
Les livres dont au moins un exemplaire est emprunté
SELECT l
FROM livres AS l
WHERE FOR ALL e IN l.lesExemplaires : e.statut = "prêté"
type du résultat : litteral set<Livre>
SELECT l
FROM livres AS l
WHERE EXISTS e IN l.lesExemplaires : e.statut = "prêté"
type du résultat :
litteral set<Livre>
16.3.14 Quantificateurs SOME, ANY et ALL
e1 op {SOME|ANY} e2
EXISTS ele IN e2 : e1 op ele
e1 op ALL e2
FOR ALL ele IN e2 : e1 op ele
27/02/22 © Robert Godin. Tous droits réservés. 37
16.3.15 Fonctions de groupe
Le nombre moyen d’exemplaires disponibles par livre
AVG (SELECT l.nbExemplairesDisponibles()
FROM livres AS l)
16.3.16 Partition avec GROUP BY
Le nombre d’exemplaires disponibles par années de parution pour les années où le nombre dépasse 100
SELECT année,
nombreDisponibles :
SUM(SELECT l.nbExemplairesDisponible() FROM partition) FROM livres AS l
GROUP BY année : l.annéeParution
HAVING SUM(SELECT l.nbExemplairesDisponible() FROM partition) > 100 type du résultat :
litteral bag<struct<année : integer, nombreDisponibles : integer>>
27/02/22 © Robert Godin. Tous droits réservés. 39
16.3.18 Tri avec ORDER BY
Les livres triés par ordre
descendant (DESC) de l’année de parution et par ordre ascendant (ASC) du titre
SELECT l
FROM livres AS l
ORDER BY l.annéeParution DESC, l.titre ASC type du résultat :
litteral set<Livre>
16.4.2.1 SCÉNARIO GLOBAL DE MANIPULATION
DE DONNÉES EN JAVA
27/02/22 © Robert Godin. Tous droits réservés. 41
16.4.2.2 DÉFINITION DE CLASSES CAPABLES DE PERSISTANCE
Dcollection, Dset, Dbag, Dlist,
Darray et Dmap
16.4.2.3 CRÉATION D'UNE
RACINE PERSISTANTE
27/02/22 © Robert Godin. Tous droits réservés. 43
16.4.2.4 NAVIGATION À PARTIR
D'UNE RACINE PERSISTANTE
16.4.2.5 REQUÊTE SIMPLE
SUR UNE DCOLLECTION
27/02/22 © Robert Godin. Tous droits réservés. 45
16.4.2.6 REQUÊTE OQL
1.5 Persistance transparente avec la norme JDO
API normalisée pour persistance transparente
Au-dessus de
– fichiers, BD SQL, XML, etc.
SQL
– correspondance déclarative entre les
types d'objets et tables
27/02/22 © Robert Godin. Tous droits réservés. 47
Exemple Livre et Editeur
27/02/22 © Robert Godin. Tous droits réservés. 49
Correspondance table-classe par
descripteur XML
Réalisation par modification
de code-octet
27/02/22 © Robert Godin. Tous droits réservés. 51
Création d’objets persistants
Utilisation d’un Extent
27/02/22 © Robert Godin. Tous droits réservés. 53
JDOQL
// Requête JDOQL
uneTransaction.begin();
Query unQuey =
unPM.newQuery(Editeur.class, "ville=\"Paris\" || ville = \"Longueuil\"" );
Collection leResultat = (Collection)unQuery.execute();
Iterator unIterateurRes = leResultat.iterator();
while (unIterateurRes.hasNext()){
Editeur unEditeur = (Editeur)unIterateurRes.next();
System.out.println(unEditeur.getNom());
}
unQuery.close();
uneTransaction.commit();
Modification
27/02/22 © Robert Godin. Tous droits réservés. 55
Supression
Hibernate
Outil de persistence transparente Java
Open source
Améliorations vs EJB 2 et JDO 1
– Plain Old Java Objects (POJO)
Héritage, associations par attributs Java
– Langage de requête HQL plus proche de SQL
– Pas de manipulation de code (introspection Java)
Support de l’API de persistance Java de
la nouvelle norme EJB3 (JSR220)
27/02/22 © Robert Godin. Tous droits réservés. 57
Classe Editeur
Classe Livre
27/02/22 © Robert Godin. Tous droits réservés. 59
Mappage objet-relationnel pour Editeur
CREATE TABLE Editeur
(nomEditeur VARCHAR(20) NOT NULL,
ville VARCHAR(20) NOT NULL,
PRIMARY KEY (nomEditeur) )
CREATE TABLE Livre
(ISBN CHAR(13) NOT NULL,
titre VARCHAR(50) NOT NULL,
anneeParution NUMBER(4) NOT NULL,
nomEditeur VARCHAR(20) NOT NULL,
PRIMARY KEY (ISBN),
FOREIGN KEY (nomEditeur) REFERENCES Editeur )
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping- 3.0.dtd">
<hibernate-mapping>
<class
name="packExempleHib.Editeur" table="Editeur">
<id name="nomEditeur"/>
<property name="ville"/>
<set name="lesLivres" inverse="true" cascade =
"all">
<key column="nomEditeur"/>
<one-to-many class="packExempleHib.Livre"/>
</set>
</class>
</hibernate-mapping>
Mappage objet-relationnel pour Livre
CREATE TABLE Editeur
(nomEditeur VARCHAR(20) NOT NULL,
ville VARCHAR(20) NOT NULL,
PRIMARY KEY (nomEditeur) )
CREATE TABLE Livre
(ISBN CHAR(13) NOT NULL,
titre VARCHAR(50) NOT NULL,
anneeParution NUMBER(4) NOT NULL,
nomEditeur VARCHAR(20) NOT NULL,
PRIMARY KEY (ISBN),
FOREIGN KEY (nomEditeur) REFERENCES Editeur
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="packExempleHib.Livre" table="Livre">
<id name="ISBN"/>
<property name="titre"/>
<property name="anneeParution"/>
<many-to-one name="editeur"
class="packExempleHib.Editeur"
column="nomEditeur" not- null="true"/>
</class>
</hibernate-mapping>
27/02/22 © Robert Godin. Tous droits réservés. 61
Singleton qui démarre Hibernate et fournit l'objet SessionFactory
public class HibernateUtil {
private static SessionFactory sessionFactory;
static { try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
} }
public static SessionFactory getSessionFactory() { return sessionFactory;
}
public static void shutdown() {
// Ferme les antémémoires et les bassins (pool) de connexions getSessionFactory().close();
}
}
27/02/22 © Robert Godin. Tous droits réservés. 62
Fichier de configuration hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property
name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property
name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:ORCL</property>
<property name="hibernate.connection.username">godin</property>
<property name="hibernate.connection.password">oracle</property>
<property name="dialect">org.hibernate.dialect.Oracle9Dialect</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!-- SQL to stdout logging -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="use_sql_comments">true</property>
<mapping resource="packExempleHib/Editeur.hbm.xml"/>
<mapping resource="packExempleHib/Livre.hbm.xml"/>
</session-factory>
27/02/22 © Robert Godin. Tous droits réservés. 63
Une première session Hibernate qui insère deux éditeurs et deux livres
Session uneSession = HibernateUtil.getSessionFactory().openSession();
Transaction uneTransaction = uneSession.beginTransaction();
Editeur unEditeur = new Editeur("Loze-Dion","Longueuil");
Editeur unAutreEditeur = new Editeur("Addison-Wesley","Reading, MA");
Livre unLivre = new Livre("1-111-1111","SGBD",2000,unEditeur);
unEditeur.getLesLivres().add(unLivre);
Livre unAutreLivre = new Livre("2-222-2222","le titre",1999,unEditeur);
unEditeur.getLesLivres().add(unAutreLivre);
uneSession.save(unEditeur);
uneSession.save(unAutreEditeur);
uneTransaction.commit();
uneSession.close(); Persistance par référence des livres associés (voir attribut cascade dans fichier de
mappage Editeur.hbm.xml)
Une deuxième session Hibernate qui lit les données de la première session et les affiche
uneSession = HibernateUtil.getSessionFactory().openSession();
uneTransaction = uneSession.beginTransaction();
List lesEditeurs =
uneSession.createQuery("from Editeur e order by e.nomEditeur asc").list();
System.out.println( lesEditeurs.size() + " editeurs trouves:" );
for ( Iterator iterEditeurs = lesEditeurs.iterator(); iterEditeurs.hasNext(); ) { Editeur unEditeurCharge = (Editeur) iterEditeurs.next();
System.out.println("Editeur:"+ unEditeurCharge.getNomEditeur() );
System.out.println("Livres de l'editeur:" );
for ( Iterator iterLivres = unEditeurCharge.getLesLivres().iterator(); iterLivres.hasNext(); ) { Livre unLivreCharge = (Livre) iterLivres.next();
System.out.println(" "+unLivreCharge.getTitre() );
} }
uneTransaction.commit();
uneSession.close();
27/02/22 © Robert Godin. Tous droits réservés. 65
Une troisième session Hibernate qui extrait les éditeurs de Paris ou Longueuil
uneSession.createQuery ("from Editeur e
where e.ville = 'Paris' or e.ville = 'Longueuil'
order by e.nomEditeur asc").list();
Une quatrième session Hibernate qui modifie le titre de ISBN:1-111-1111
uneTransaction = uneSession.beginTransaction();
List lesLivres =
uneSession.createQuery("from Livre l where l.ISBN = '1-111-1111'
").list();
unLivre = (Livre)lesLivres.iterator().next();
unLivre.setTitre("UnNouveauTitre");
uneTransaction.commit();
27/02/22 © Robert Godin. Tous droits réservés. 67