Cours Java Persistence API avec Hibernate pour débutant
![Cours Java Persistence API avec Hibernate pour débutant](/images/remos_downloads/id-11804.11804.pdf_thumb_prev.jpg)
Achref El Mouelhi
Docteur de l’universite d’Aix-Marseille´
Chercheur en Programmation par contrainte (IA) Ingenieur en G´ enie logiciel´
Plan
Introduction
Creation d’une connexion´
Hibernate avec les fichiers de mapping
Hibernate avec les annotations JPA
Insertion
Selection selon l’identifiant´
Modification
Suppression
Selection avec crit´ eres`
Autres operations´
Autres annotations JPA
Plan
SQL et HQL
Relation entre entites´
OneToOne
ManyToOne
OneToMany
ManyToMany
Inheritance
Classes incorporables
Methodes´ callback
Restructuration du code
JPA : Java Persistence API
ensemble d’interfaces standardise par Sun, qui permet´ l’organisation des donnees´ propose par JSR (Java Specification Requests)´
s’appuyant sur l’utilisation des annotations pour definir le lien´ entre Entity (classe) et table (en base de donnees relationnelle)´
et sur le gestionnaire EntityManager pour gerer les donn´ ees´
(insertion, modification )
Ajouter une premiere d` ependance pour Hibernate dans´
<!-- https: --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.1.7.Final</version> </dependency> |
Ajouter une premiere d` ependance pour Hibernate dans´
<!-- https: --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.1.7.Final</version> </dependency> |
Ajouter une deuxieme pour le driver de MySQL`
<!-- https:--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> |
14 / 122
Ajouter une premiere d` ependance pour Hibernate dans´
<!-- https: --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.1.7.Final</version> </dependency> |
Ajouter une deuxieme pour le driver de MySQL`
<!-- https:--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> |
Pour mettre a jour ces d` ependances dans le projet, il faut faire´ Maven > Update Project
Quelle que soit la solution, il faut que la valeur choisie pour
Hibernate version correspond a celle de la d` ependance ajout´ ee´ dans
Si on veut remplir le formulaire champ par champ
Choisir MySQL de la liste Database dialect
Selectionner le driver MySQL,´ .Driver, de la liste Driver Class,
Choisir l’URL de connexion
jdbc:mysql://<host><:port>/<database> de Connection URL et la remplacer par jdbc:mysql://localhost:3306/hibernate
Saisir le nom d’utilisateur dans Username et le mot de passe dans Password
Valider et aller verifier les donn´ ees dans le fichier XML g´ en´ er´ e´
Contenu du fichier
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPEhibernate-configurationPUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" " "> <hibernate-configuration> <session-factory name=""> <property name="hibernate.connection.driver_class">com.mysql. jdbc.Driver</property> <property name="">jdbc:mysql:// localhost:3306/hibernate</property> <property name="hibernate.connection.username">root</property > <property name="hibernate.connection.password">root</property > <property name="hibernate.dialect">org.hibernate.dialect. MySQLDialect</property> </session-factory> </hibernate-configuration> |
On peut aussi ajouter la propriet´ e´ qui peut prendre comme valeur
create : cree les tables, les donn´ ees pr´ ec´ edemment pr´ esentes´ dans les tables seront perdues.
update : met a jour les tables avec les valeurs donn` ees. si les´ tables ne sont pas presentes dans la base de donn´ ees, elles´ seront creées.´
validate : si les tables ne sont pas presentes dans la base de´ donnees, elles ne seront pas cr´ eées et une exception sera lev´ ee.´
create-drop : creer les tables en d´ etruisant les donn´ ees´ prec´ edemment pr´ esentes. Les tables de la base de donn´ ees´ seront aussi supprimees lorsque la SessionFactory est ferm´ ee (´ a` utiliser pour tester).
Nouveau contenu du fichier
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPEhibernate-configurationPUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" ""> <hibernate-configuration> <session-factory name=""> <property name="hibernate.connection.driver_class">. Driver</property> <property name="">jdbc:mysql://localhost:3306 /hibernate</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect </property> <property name="">update</property> <property name="show_sql">true</property> </session-factory> </hibernate-configuration> |
Creons une classe´ Personne dans org.eclipse.model
public classPersonne {private intnum;privateString nom;privateString prenom; public intgetNum() {returnnum; }public voidsetNum(intnum) {this.num = num; }publicString getNom() {returnnom; }public voidsetNom(String nom) {this.nom = nom; }publicString getPrenom() {returnprenom; }public voidsetPrenom(String prenom) {this.prenom = prenom; } } |
Exemple de contenu du fichier
<?xml version="1.0"?> <!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN" ""> <!-- Generated 2 ao?t 2018 06:34:34 by Hibernate Tools 3.5.0.Final --> <hibernate-mapping> <class name="org.eclipse.model.Personne" table="PERSONNE"> <id name="num" type="int"> <column name="NUM" /> <generator class="assigned" /> </id> <property name="nom" type=".String"> <column name="NOM" /> </property> <property name="prenom" type=".String"> <column name="PRENOM" /> </property> </class> </hibernate-mapping> |
Remplacer <generator class="assigned" /> par <generator class="increment"
/> pour que la cle primaire soit auto-incr´ ementale.´
Nouveau contenu du fichier
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPEhibernate-configurationPUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" ""> <hibernate-configuration> <session-factory name=""> <property name="hibernate.connection.driver_class">. Driver</property> <property name="">jdbc:mysql://localhost:3306 /hibernate</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect </property> <property name="">update</property> <property name="show_sql">true</property> <mapping resource=""/> </session-factory> </hibernate-configuration> |
Configuration configuration =newConfiguration(); |
Configuration configuration =newConfiguration();
Pour charger le fichier(situe dans´ src/main/java)
configuration.configure();
26 / 122
Configuration configuration =newConfiguration();
Pour charger le fichier(situe dans´ src/main/java)
configuration.configure();
Si le fichier est situe dans un autre emplacement (par exemple, dans´ org.eclipse.model), on peut faire
configuration.configure("");
26 / 122
Configuration configuration =newConfiguration();
Pour charger le fichier(situe dans´ src/main/java)
configuration.configure();
Si le fichier est situe dans un autre emplacement (par exemple, dans´ org.eclipse.model), on peut faire
configuration.configure("");
On peut fusionner les deux etapes pr´ ec´ edentes´
Configuration configuration =newConfiguration().configure();
26 / 122
Configuration configuration =newConfiguration();
Pour charger le fichier(situe dans´ src/main/java)
configuration.configure();
Si le fichier est situe dans un autre emplacement (par exemple, dans´ org.eclipse.model), on peut faire
configuration.configure("");
On peut fusionner les deux etapes pr´ ec´ edentes´
Configuration configuration =newConfiguration().configure();
Ajouter l’entite´ a l’objet de configuration`
configuration.addClass(Personne.class);
26 / 122
Construire l’usine de gestionnaire d’entite´ a partir de l’objet de configuration`
SessionFactory sessionFactory = configuration.buildSessionFactory();
Construire l’usine de gestionnaire d’entite´ a partir de l’objet de configuration`
SessionFactory sessionFactory = configuration.buildSessionFactory();
Obtenir le gestionnaire d’entite´
Session session = sessionFactory.openSession();
Construire l’usine de gestionnaire d’entite´ a partir de l’objet de configuration`
SessionFactory sessionFactory = configuration.buildSessionFactory();
Obtenir le gestionnaire d’entite´
Session session = sessionFactory.openSession();
Demarrer une transaction´
Transaction transaction = session.beginTransaction();
Construire l’usine de gestionnaire d’entite´ a partir de l’objet de configuration`
SessionFactory sessionFactory = configuration.buildSessionFactory();
Obtenir le gestionnaire d’entite´
Session session = sessionFactory.openSession();
Demarrer une transaction´
Transaction transaction = session.beginTransaction();
Inserer un objet dans la base de donn´ ees´
session.persist(personne);
Construire l’usine de gestionnaire d’entite´ a partir de l’objet de configuration`
SessionFactory sessionFactory = configuration.buildSessionFactory();
Obtenir le gestionnaire d’entite´
Session session = sessionFactory.openSession();
Demarrer une transaction´
Transaction transaction = session.beginTransaction();
Inserer un objet dans la base de donn´ ees´
session.persist(personne);
Terminer la transaction et fermer les flux
transaction.commit(); session.close(); sessionFactory.close();
Mettons tout c¸a dans le main de
Personne personne =newPersonne(); personne.setNom("travolta"); personne.setPrenom("john"); Configuration configuration =newConfiguration().configure(); configuration.addClass(Personne.class); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(personne); transaction.commit(); session.close(); sessionFactory.close(); |
28 / 122
Mettons tout c¸a dans le main de
Personne personne =newPersonne(); personne.setNom("travolta"); personne.setPrenom("john"); Configuration configuration =newConfiguration().configure(); configuration.addClass(Personne.class); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Les import necessaires´
importorg.hibernate.Session;importorg.hibernate.SessionFactory;importorg.hibernate.Transaction;import.Configuration;
On peut aussi enregistrer la classe a utiliser (ici` Personne) dansen ajoutant une nouvelle balise <mapping class="org.eclipse.model.Personne"/>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPEhibernate-configurationPUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" ""> <hibernate-configuration> <session-factory name=""> <property name="hibernate.connection.driver_class">. Driver</property> <property name="">jdbc:mysql://localhost:3306 /hibernate</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect </property> <property name="">update</property> <property name="show_sql">true</property> <mapping resource=""/> <mapping class="org.eclipse.model.Personne"/> </session-factory> </hibernate-configuration> |
Nous pouvons ainsi supprimer la ligne configuration.addClass(Personne.class)
Personne personne =newPersonne(); personne.setNom("travolta"); personne.setPrenom("john"); Configuration configuration =newConfiguration(). configure(); //configuration.addClass(Personne.class); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Chaque entite doit´ etre dˆ eclar´ ee´
Soit dans en ajoutant la ligne
<mapping class="org.eclipse.model.Personne" />
Soit lorsqu’on veut persister des donnees en ajoutant la ligne´ configuration.addClass(Personne.class) ou configuration.addAnnotatedClass(Personne.class)
Avant de commencer
Supprimer le fichier de mapping
Supprimer la ligne <mapping
resource=""/> dans (Ne pas supprimer <mapping class="org.eclipse.model.Personne"/>)
Supprimer et recreer la base de donn´ ees´ hibernate
Ajoutons les annotations suivantes dans la classe Personne
packageorg.eclipse.model; importjavax.persistence.Entity;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;import; @Entitypublic classPersonne { @Id @GeneratedValue (strategy=GenerationType.IDENTITY)private intnum; privateString nom;privateString prenom; // + getters setters et toString } |
Pour ajouter une personne dans la base de donnees´
Personne personne =newPersonne(); personne.setNom("travolta"); personne.setPrenom("john"); Configuration configuration =newConfiguration(). configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(personne); transaction.commit(); session.close(); sessionFactory.close(); |
On peut utiliser save pour recup´ erer la valeur de la cl´ e primaire qui a´ et´ e´ attribue au tuple ajout´ e dans la base de donn´ ees´
Personne personne =newPersonne(); personne.setNom("travolta"); personne.setPrenom("john"); Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Integer cle = (personne); transaction.commit(); session.close(); sessionFactory.close(); .println(cle); |
Si on n’avait pas declar´ e l’entit´ e´ Personne dans(<mapping class="org.eclipse.model.Personne"></mapping>), on peut, ici, ajouter la ligne configuration.addAnnotatedClass(Personne.class)
Personne personne =newPersonne(); personne.setNom("travolta"); personne.setPrenom("john"); Configuration configuration =newConfiguration().configure(); configuration.addAnnotatedClass(Personne.class); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Pour chercher une personne (avec load)
Configuration configuration =newConfiguration(). configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Personne personne1 = (Personne.class, 1); .println(personne1); transaction.commit(); session.close(); sessionFactory.close(); |
Pour chercher une personne (avec get)
Configuration configuration =newConfiguration(). configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Personne personne1 = (Personne.class, 1); .println(personne1); transaction.commit(); session.close(); sessionFactory.close(); |
Pour modifier une personne
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Personne personne3 = (Personne.class, 1); personne3.setNom("Abruzzi"); session.flush(); transaction.commit(); session.close(); sessionFactory.close(); |
La methode´ flush() ne prend pas de parametre. Donc elle envoie tous les` changements des entites manag´ ees dans la base de donn´ ees´
On peut aussi utiliser persist() ou save() pour enregistrer les modifications
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Personne personne3 = (Personne.class, 2); personne3.setNom("Abruzzi"); session.persist(personne3); transaction.commit(); session.close(); sessionFactory.close(); |
Les methodes´ save(obj) et persist(obj) prennent en parametre l’objet` modifie et´ a sauvegarder dans la base de donn` ees´
Si l’objet est detach´ e (n’est pas attach´ e´ a une session), le persister entraine sa cr` eation et´ non pas sa modification
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Personne personne4 =newPersonne(); personne4.setNom("Denzel"); personne4.setNum(1); personne4.setPrenom("Washington"); session.persist(personne4); transaction.commit(); session.close(); sessionFactory.close(); |
Malgre l’existence de l’identifiant 1, un nouveau tuple sera cr´ eé avec un identifiant´ different de 1 (pareil pour´ save())
Suppression
Pour supprimer une personne
Configuration configuration =newConfiguration(). configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Personne personne3 = (Personne.class, 1); session.delete(personne3); transaction.commit(); session.close(); sessionFactory.close(); |
Selection avec crit´ eres`
Pour recup´ erer la liste de toutes les personnes´
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Criteria criteria = session.createCriteria(Personne.class); List<Personne> personnes = (List<Personne>) ();for(Personne personne : personnes) .println(personne); transaction.commit(); session.close(); sessionFactory.close(); |
N’oublions pas d’ajouter toString() dans la classe Personne.
Selection avec crit´ eres`
Pour recup´ erer une liste de personnes selon un crit´ ere (ici le` nom)
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); String string = "travolta"; Criteria criteria = session.createCriteria(Personne.class); criteria = (("nom", string)); List<Personne> personnes = (List<Personne>) ();for(Personne personne : personnes) .println(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Autres methodes de la session´
refresh(entity) : permet de synchroniser l’etat de l’entit´ e´ passee en param´ etre (` entity) avec son etat en base de´ donnees.´
evict(entity) : permet de detacher l’entit´ e pass´ ee en´ parametre (` entity) de l’EntityManager qui la gere.`
merge(entity) : permet d’attacher l’entite pass´ ee en param´ etre`
(entity), ger´ ee par un autre´ EntityManager, a` l’EntityManager courant.
Exemple avec utilisation de refresh()
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); //on suppose que John Wick avec un num 1 existe dans la BDPersonne p = (Personne.class, 1); p.setNom("Travolta"); session.refresh(p); .println("le nom est " + p.getNom()); // affiche le nom est Wick transaction.commit(); session.close(); sessionFactory.close(); // si on supprime session.refresh(p); Travolta sera affiché |
Exemple avec utilisation de evict()
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); // on suppose que John Wick avec un num 1 existe dans la BDPersonne p = (Personne.class, 1); p.setNom("Travolta"); session.evict(p);// p n’est plus géré par sessionsession.flush(); transaction().commit(); Personne p1 = (Personne.class, 1); .println("le nom est " + p1.getNom()); // affiche le nom est Wicksession.close(); sessionFactory.close(); |
Autres annotations
Annotation designation´
@Entity permet de qualifier la classe comme entite´
@Id indique l’attribut qui correspond a la cl` e primaire de la table´
@Table decrit la table d´ esign´ ee par l’entit´ e´
@Column definit les propri´ et´ es d’une colonne´
@IdClass indique que l’entite annot´ ee contient une cl´ e compos´ ee´ les champs constituant la cle seront annot´ e par´ @Id
@GeneratedValue s’applique sur les attributs annotes par @Id´ permet la gen´ eration automatique de la cl´ e primaire´
Autres annotations
Annotation designation´
@Entity permet de qualifier la classe comme entite´
@Id indique l’attribut qui correspond a la cl` e primaire de la table´
@Table decrit la table d´ esign´ ee par l’entit´ e´
@Column definit les propri´ et´ es d’une colonne´
@IdClass indique que l’entite annot´ ee contient une cl´ e compos´ ee´ les champs constituant la cle seront annot´ e par´ @Id
@GeneratedValue s’applique sur les attributs annotes par @Id´ permet la gen´ eration automatique de la cl´ e primaire´
// la classe Personne
@IdClass(PersonnePK.class)
@Entitypublic classPersonne {
@IdprivateString nom; @IdprivateString prenom;
// ensuite getters, setters et constructeur
// la classe PersonnePKpublic classPersonnePK {
@IdprivateString nom; @IdprivateString prenom;
// ensuite getters, setters, constructeur sans parametres et constructeur avec deux parametres nom et prenoms
Attributs de l’annotation @Column
Attribut designation´
name permet de definir le nom de la colonne´
s’il est different de celui de l’attribut´
length permet de fixer la longueur d’une chaˆ?ne de caracteres` unique indique que la valeur d’un champ est unique
nullable precise si un champ est null (ou non)´
@Table( name="personne", uniqueConstraints={ @UniqueConstraint(name="nom_prenom", columnNames ={"nom", "prenom"}) } ) |
L’annotation @Transient
L’attribut annote par´ @Transient n’aura pas de colonne associee´ dans la table correspondante a l’entit` e en base de donn´ ees.´
Pour executer une requ´ ete SQLˆ
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); String sqlRequete = "select * from Personne"; SQLQuery query = session.createSQLQuery(sqlRequete); query.addEntity(Personne.class); List<Personne> personnes = (List<Personne>) ();for(Personne personne : personnes) .println(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Sans query.addEntity(Personne.class), on ne peut faire le cast List
<Personne> personnes = (List <Personne>) ()
On peut aussi executer une requ´ ete SQL paramˆ etr´ ee´
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); String sqlRequete = "select * from Personne where nom = :nom"; SQLQuery query = session.createSQLQuery(sqlRequete); query.addEntity(Personne.class); query.setParameter("nom", "Abruzzi"); List<Personne> personnes = (List<Personne>) ();for(Personne personne : personnes) .println(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Les requetes nommˆ ees : exemple (on commence tout d’abord par´ definir la requ´ ete dans l’entitˆ e)´
@Entity @NamedQuery( name="findByNomPrenom", query="SELECT p FROM Personne p WHERE p.nom = : nom and p.prenom = :prenom" )public class Personne { // le code précédent } |
Les requetes nommˆ ees : exemple (ensuite nous l’utiliserons)´
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Query query = session.getNamedQuery("findByNomPrenom"); query.setParameter("nom", "Abruzzi"); query.setParameter("prenom", "John"); List<Personne> personnes = (List<Personne>) ();for(Personne personne : personnes) .println(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Et si on veut definir plusieurs requ´ etes nommˆ ees´
@Entity @NamedQueries({ @NamedQuery( name="findByNomPrenom", query="SELECT p FROM Personne p WHERE p.nom = :nom and p. prenom = :prenom" ), @NamedQuery( name="findByPrenom", query="SELECT p FROM Personne p WHERE p.prenom = :prenom" ), }) public classPersonne { // le code précédent } |
Et si on veut definir plusieurs requ´ etes nommˆ ees´
@Entity @NamedQueries({ @NamedQuery( name="findByNomPrenom", query="SELECT p FROM Personne p WHERE p.nom = :nom and p. prenom = :prenom" ), @NamedQuery( name="findByPrenom", query="SELECT p FROM Personne p WHERE p.prenom = :prenom" ), }) public classPersonne { // le code précédent } |
60 / 122
61 / 122
Utiliser HQL pour recup´ erer une liste de personnes ayant un´ nom = travolta
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); String hql = "select p from Personne p where nom = :nom"; String string = "travolta"; Query query = session.createQuery(hql); query.setParameter("nom", string); List<Personne> personnes = (List<Personne>) ();for(Personne personne : personnes) .println(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Simplifier la requete prˆ ec´ edente´
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); String hql = "from Personne where nom = :nom"; String string = "travolta"; Query query = session.createQuery(hql); query.setParameter("nom", string); List<Personne> personnes = (List<Personne>) ();for(Personne personne : personnes) .println(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Hibernate : documentation officielle (en franc¸ais)
Quatre (ou trois) relations possibles
OneToOne : chaque objet d’une premiere classe est en relation` avec un seul objet de la deuxieme classe`
OneToMany : chaque objet d’une premiere classe peut` etre enˆ relation avec plusieurs objets de la deuxieme classe (la` reciproque est´ ManyToOne)
ManyToMany : chaque objet d’une premiere classe peut` etre enˆ relation avec plusieurs objets de la deuxieme classe et` inversement
L’entite´ Adresse dans org.eclipse.model
@Entitypublic class Adresse { @Idprivate String rue;private String codePostal;private String ville; // + getters, setters et toString } |
Modifier l’entite Personne´
@Entitypublic classPersonne { @Idprivate intnum;privateString nom;privateString prenom; @OneToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE}) @JoinColumn(name="rue", referencedColumnName="rue", nullable=false)privateAdresse adresse; // + les getters/setters de chaque attribut } |
Modifier l’entite Personne´
@Entitypublic classPersonne { @Idprivate intnum;privateString nom;privateString prenom; @OneToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE}) @JoinColumn(name="rue", referencedColumnName="rue", nullable=false)privateAdresse adresse; // + les getters/setters de chaque attribut } |
@OneToOne(cascade={CascadeType.PERSIST, CascadeType. REMOVE}) |
@JoinColumn(name="rue", referencedColumnName="rue", nullable=false)
Testons l’ajout d’une personne
/* Adresse */ Adresse adresse =newAdresse(); adresse.setRue("Lyon"); adresse.setCodePostal("13015"); adresse.setVille("Marseille"); /* Personne */ Personne personne =newPersonne(); personne.setAdresse(adresse); personne.setNom("Ego"); personne.setPrenom("Paul"); /* Persistance */ Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(personne); transaction.commit(); session.close(); sessionFactory.close(); |
Remplacer persist() par save() et verifier que c¸a ne marche pas´
Testons l’ajout avec save
Adresse adresse =newAdresse(); adresse.setRue("Paradis"); adresse.setCodePostal("13015"); adresse.setVille("Marseille"); Personne personne =newPersonne(); personne.setAdresse(adresse); personne.setNom("Wick"); personne.setPrenom("John"); Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); (adresse); (personne); transaction.commit(); session.close(); sessionFactory.close(); |
Sans la precision suivante´
@OneToOne(cascade={CascadeType.PERSIST, CascadeType. REMOVE}) |
Sans la precision suivante´
@OneToOne(cascade={CascadeType.PERSIST, CascadeType. REMOVE}) |
Il fallait persister l’objet adresse avant l’objet personne
Transaction transaction = session.beginTransaction(); session.persist(adresse); session.persist(personne); transaction.commit();
Adresse adresse =newAdresse(); adresse.setRue("New York"); adresse.setCodePostal("13015"); adresse.setVille("Marseille"); Personne personne =newPersonne(); personne.setAdresse(adresse); personne.setNom("Messi"); personne.setPrenom("Thiago"); Personne personne2 =newPersonne(); personne2.setAdresse(adresse); personne2.setNom("Messi"); personne2.setPrenom("Leo"); Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(personne); session.persist(personne2); transaction.commit(); session.close(); sessionFactory.close(); |
Il faut changer l’attribut adresse par une liste d’adresses
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE})private List <Adresse> adresses =new ArrayList < Adresse> (); |
Il faut changer l’attribut adresse par une liste d’adresses
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE})private List <Adresse> adresses =new ArrayList < Adresse> (); |
N’oublions pas de supprimer ce code de l’entite´ Personne
@OneToOne(cascade={CascadeType.PERSIST, CascadeType.
REMOVE})
@JoinColumn(name="rue", referencedColumnName="rue", nullable=false)private Adresse adresse;
// les getters/setters de chaque attribut
Ensuite il faut gen´ erer le getter et le setter d’´ adresses
il faut aussi gen´ erer la m´ ethode´ add et remove qui permettent d’ajouter ou de supprimer une adresse pour un objet personne (Dans Source, choisir Generate Delegate Methods).
Renommer add en addAdresse et remove en removeAdresse
Adresse a1 =newAdresse(); a1.setRue("Estaque"); a1.setCodePostal("13016"); a1.setVille("Marseille"); Adresse a2 =newAdresse(); a2.setRue("Merlan"); a2.setCodePostal("13013"); a2.setVille("Marseille"); Personne p1 =newPersonne(); p1.setNom("Wick"); p1.setPrenom("John"); p1.addAdresse(a1); p1.addAdresse(a2); Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(personne); transaction.commit(); session.close(); sessionFactory.close(); |
On peut aussi definir si les objets de l’entit´ e inverse (ici´ Adresse) seront charges dans l’entit´ e propri´ etaire (ici´ Personne). Il faut ajouter dans l’annotation l’attribut fetch :
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE}, fetch = FetchType.CONSTANTE)privateList <Adresse> adresses =newArrayList <Adresse> ();
On peut aussi definir si les objets de l’entit´ e inverse (ici´ Adresse) seront charges dans l’entit´ e propri´ etaire (ici´ Personne). Il faut ajouter dans l’annotation l’attribut fetch :
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE}, fetch = FetchType.CONSTANTE)
privateList <Adresse> adresses =newArrayList <Adresse> ();
Deux valeurs possibles pour CONSTANTE
EAGER : les objets de l’entite´ Adresse en relation avec un objet personne de l’entite´ Personne seront charges imm´ ediatement.´
LAZY (par defaut) : les objets de l’entit´ e´ Adresse en relation avec un objet personne de l’entite´ Personne seront charges seulement lorsqu’ils sont´ demandes (quand on fait´ personne.getAdresses()).
84 / 122
Par defaut, c’est´ LAZY (rien a modifier dans l’entit` e´ Personne)
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Criteria criteria = session.createCriteria(Personne.class); List<Personne> personnes = (List<Personne>) ();for(Personne personne : personnes) { .println(personne); } session.close(); sessionFactory.close(); |
85 / 122
Par defaut, c’est´ LAZY (rien a modifier dans l’entit` e´ Personne)
Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration. buildSessionFactory(); Session session = sessionFactory.openSession(); Criteria criteria = session.createCriteria(Personne.class); List<Personne> personnes = (List<Personne>) ();for(Personne personne : personnes) { .println(personne); } session.close(); sessionFactory.close(); |
Mettre le chargement a` EAGER et tester
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE}, fetch = FetchType.EAGER)privateList <Adresse> adresses =newArrayList <Adresse> ();
85 / 122
Remarque
Possible d’avoir des tuples dupliques avec le chargement´ EAGER
En effet, Hibernate fait une jointure interne sur la table de jointure
(personneadresse) ce qui cause des eventuelles duplications´
(par exemple si une personne avait plusieurs adresses)
86 / 122
Remarque
Possible d’avoir des tuples dupliques avec le chargement´ EAGER
En effet, Hibernate fait une jointure interne sur la table de jointure
(personneadresse) ce qui cause des eventuelles duplications´
(par exemple si une personne avait plusieurs adresses)
Nous pouvons rectifier le probleme de duplication en ajoutant` l’annotation suivante
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE}, fetch = FetchType.EAGER) @Fetch(FetchMode.SELECT) private List <Adresse> adresses =new ArrayList < Adresse> (); |
Creation de l’entit´ e Sport´
public classSport { @IdprivateString nom;privateString type;private staticfinallongserialVersionUID = 1L;publicSport() { super(); }publicString getNom() {returnnom; }public voidsetNom(String nom) {this.nom = nom; }publicString getType() {returntype; }public voidsetType(String type) {this.type = type; } } |
Ajoutons le ManyToMany dans la classe Personne
@Entitypublic classPersonne implements Serializable { // code précédent @ManyToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE})privateList <Sport> sports =newArrayList <Sport> (); publicList<Sport> getSports() {returnsports; }public voidsetSports(List<Sport> sports) {this.sports = sports; }publicboolean addSport(Sport sport) {return(sport); }publicboolean removeSport(Sport sport) {returnsports.remove(sport); } } |
Personne p1 =newPersonne(); Personne p2 =newPersonne(); p1.setNom("Voight"); p1.setPrenom("Bill"); p2.setNom("Bob"); p2.setPrenom("Joe"); Sport s1 =newSport(); Sport s2 =newSport(); Sport s3 =newSport(); s1.setNom("football"); s2.setNom("tennis"); s3.setNom("box"); s1.setType("collectif"); s2.setType("individuel"); s3.setType("collectif ou individuel"); p1.addSport(s1); p1.addSport(s3); p2.addSport(s1); p2.addSport(s2); p2.addSport(s3); Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(p1); session.persist(p2); transaction.commit(); session.close(); sessionFactory.close(); |
Si la classe association est porteuse de donnees´
Par exemple : la relation (ArticleCommande) entre Commande et Article
Il faut preciser la quantit´ e de chaque article dans une commande´
94 / 122
Modifier l’entite inverse´ Sport
@Entitypublic classSportimplementsSerializable { @IdprivateString nom;privateString type; @ManyToMany(mappedBy="sports") privateList <Personne> personnes =newArrayList <Personne> (); // ajouter les getter, setter, add et remove } |
Nouveau code des methodes´ addSport et removeSport de la classe Personne
public voidaddSport(Sport sport) { (sport); sport.getPersonnes().add(this);
}
public voidremoveSport(Sport sport) { sports.remove(sport); sport.getPersonnes().remove(this);
}
Nouveau code des methodes´ addSport et removeSport de la classe Personne
public voidaddSport(Sport sport) { (sport); sport.getPersonnes().add(this);
}
public voidremoveSport(Sport sport) { sports.remove(sport); sport.getPersonnes().remove(this);
}
Nouveau code des methodes´ addPersonne et removePersonne de la classe Sport
public voidaddPersonne(Personne personne) { (personne); personne.getSports().add(this);
}
public voidremovePersonne(Personne personne) { personnes.remove(personne); personne.getSports().add(this);
}
96 / 122
Ainsi, on peut faire : (Supprimer et recreer la base de donn´ ees)´
// tout le code précédent du main +for (Personne personne : s1.getPersonnes()) .println(personne.getNom()); |
97 / 122
Ainsi, on peut faire : (Supprimer et recreer la base de donn´ ees)´
// tout le code précédent du main +for (Personne personne : s1.getPersonnes()) .println(personne.getNom()); |
Pour definir une relation bidirectionnelle entre deux entit´ es´
si dans l’entite propri´ etaire la relation d´ efinie est´ OneToMany, alors dans l’entite inverse la relation sera´ ManyToOne, et inversement.
si dans l’entite propri´ etaire la relation d´ efinie est´ OneToOne, alors dans l’entite inverse la relation sera aussi´ OneToOne.
si dans l’entite propri´ etaire la relation d´ efinie est´ ManyToMany, alors dans l’entite inverse la relation sera aussi´ ManyToMany.
Pour indiquer comment transformer les classes mere et filles en tables`
Il faut utiliser l’annotation @Inheritance
@Entity @DiscriminatorValue(value="ETU")public classEtudiantextendsPersonne { privateString niveau; publicString getNiveau() {returnniveau; } public voidsetNiveau(String niveau) {this.niveau = niveau; } } | @Entity @DiscriminatorValue(value="ENS")public classEnseignantextendsPersonne { private intsalaire; public intgetSalaire() {returnsalaire; } public voidsetSalaire(intsalaire) {this.salaire = salaire; } } |
La classe Personne
@Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="TYPE_PERSONNE") @DiscriminatorValue(value="PERS")public classPersonne { // + tout le code précédent } |
La classe Etudiant La classe Enseignant Et pour tester
/* Personne */ Personne personne =newPersonne(); personne.setNom("Guardiola"); personne.setPrenom("Pep"); /* Enseignant */ Enseignant enseignant =newEnseignant(); enseignant.setNom("Ferguson"); enseignant.setPrenom("Sir"); enseignant.setSalaire(10000); /* étudiant */ Etudiant etudiant =newEtudiant(); etudiant.setNom("Mourinho"); etudiant.setPrenom("Jose"); etudiant.setNiveau("Ligue 1"); /* Persistance */ Configuration configuration =newConfiguration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); session.persist(personne); session.persist(etudiant); session.persist(enseignant); transaction.commit(); session.close(); sessionFactory.close(); |
Et si on deplace les attributs´ nom et prénom dans une nouvelle classe NomComplet
@Embeddablepublic classNomComplet {privateString nom;privateString prenom;publicString getNom() {returnnom; }public voidsetNom(String nom) {this.nom = nom; }publicString getPrenom() {returnprenom; }public voidsetPrenom(String prenom) {this.prenom = prenom; } @OverridepublicString toString() {return"NomComplet [nom=" + nom + ", prenom=" + prenom + "]"; } } |
L’entite´ Personne devient ainsi :
@Entitypublic classPersonne { @Id @GeneratedValue (strategy=GenerationType.IDENTITY)private intnum; privateNomComplet nomComplet; public intgetNum() {returnnum; }public voidsetNum(intnum) {this.num = num; }publicNomComplet getNomComplet() {returnnomComplet; }public voidsetNomComplet(NomComplet nomComplet) {this.nomComplet = nomComplet; } |
Les classes incorporables : pas de table correspondante en BD
Personne personne =newPersonne(); NomComplet nomComplet =newNomComplet(); nomComplet.setNom("travolta"); nomComplet.setPrenom("john"); personne.setNomComplet(nomComplet); Transaction transaction = session.beginTransaction(); transaction.begin(); session.persist(personne); transaction.commit(); |
Les classes incorporables : pas de table correspondante en BD
Personne personne =newPersonne(); NomComplet nomComplet =newNomComplet(); nomComplet.setNom("travolta"); nomComplet.setPrenom("john"); personne.setNomComplet(nomComplet); Transaction transaction = session.beginTransaction(); transaction.begin(); session.persist(personne); transaction.commit(); |
Il n’y aura pas de table NomComplet, les attributs nom et prénom seront transformes en colonne dans la table´ Personne
Une methode´ callback
Une methode´ callback est une methode qui sera appel´ ee avant´ ou apres un` ev´ enement survenu sur une entit` e´
On utilise les annotations pour specifier quand la m´ ethode´ callback sera appelee´
Une methode´ callback
Une methode´ callback est une methode qui sera appel´ ee avant´ ou apres un` ev´ enement survenu sur une entit` e´
On utilise les annotations pour specifier quand la m´ ethode´ callback sera appelee´
C’est comme les triggers en SQL
112 / 122
@PrePersist : avant qu’une nouvelle entite soit persist´ ee.´
@PostPersist : apres l’enregistrement de l’entit` e dans la base´ de donnees.´
@PostLoad : apres le chargement d’une entit` e de la base de´ donnees.´
@PreUpdate : avant que la modification d’une entite soit´ enregistree en base de donn´ ees.´
@PostUpdate : apres que la modification d’une entit` e est´ enregistree en base de donn´ ees.´
@PreRemove : avant qu’une entite soit supprim´ ee de la base de´ donnee.´
@PostRemove : apres qu’une entit` e est supprim´ ee de la base de´ donnee.´
Exemple : l’entite´ Personne
public classPersonneimplementsSerializable { @Idprivate intnum;privateString nom;privateString prenom;private intnbrMAJ=0;// pour calculer le nombre de modification public intgetNbrMAJ() {returnnbrMAJ; }public voidsetNbrMAJ(intnbrMAJ) {this.nbrMAJ = nbrMAJ; } @PostUpdatepublic voidupdateNbrMAJ() {this.nbrMAJ++; } // les autres getters, setters et constructeur |
02 Aout 2018, Aix-en-Provenceˆ 114 / 122
Personne p1 =newPersonne(); p1.setNom("Wick"); p1.setPrenom("John"); session.getTransaction().begin(); session.persist(p1); session.getTransaction().commit(); .println("nbrMAJ = " + p1.getNbrMAJ()); // affiche nbrMAJ = 0 p1.setNom("Travolta"); session.getTransaction().begin(); session.flush(); session.getTransaction().commit(); p1.setNom("Abruzzi"); session.getTransaction().begin(); session.flush(); session.getTransaction().commit(); .println("nbrMAJ = " + p1.getNbrMAJ()); // affiche nbrMAJ = 2 |
Organisation du code
Creer une classe´ HibernateUtil qui se charge de lire le fichier et de construire un objet de SessionFactory
Creer une deuxi´ eme classe g` en´ erique´ GenericDao qui recup´ ere` l’objet de SessionFactory construit par HibernateUtil et l’utilise pour faire le CRUD pour l’entite pass´ e comme param´ etre` gen´ erique´
Pour chaque entite, on cr´ ee une classe´ Dao qui etend´
GenericDao
La classe HibernateUtil
packageorg.eclipse.config; importorg.hibernate.SessionFactory;import.Configuration; public classHibernateUtil { private staticSessionFactory sessionFactory; public staticSessionFactory getSessionFactory() { Configuration configuration =newConfiguration().configure ();returnconfiguration.buildSessionFactory(); } } |
La classe GenericDao
package; import;importorg.hibernate.Session;importorg.hibernate.Transaction; public classGenericDao <T,P> { protectedSession session;privateClass<T> entity; publicGenericDao(Class<T> entity, Session session) { this.session = session;this.entity = entity; }publicSession getSession() {returnsession; } publicP save(T obj)throwsException { Transaction tx =null; P result;try{ tx = session.beginTransaction(); result = (P) (obj); tx.commit(); }catch(Exception e) {if(tx !=null) tx.rollback();throwe; }returnresult; } |
La classe GenericDao (suite)
public voidupdate(T obj)throwsException { Transaction tx =null;try{ tx = session.beginTransaction(); session.saveOrUpdate(obj); tx.commit(); }catch(Exception e) {if(tx !=null) tx.rollback();throwe; } } public voiddelete(T obj)throwsException { Transaction tx =null;try{ tx = session.beginTransaction(); session.delete(obj); tx.commit(); }catch(Exception e) {if(tx !=null) tx.rollback();throwe; } }publicT findById(intid) {return(entity, id); }publicList<T> findAll() {return(List<T>) session.createQuery("from " + entity.getName()).list(); } } |
Pour les cles primaires des entit´ es, on utilise que les types objets´
public classPersonne {privateInteger num;privateString nom;privateString prenom; publicInteger getNum() {returnnum; }public voidsetNum(Integer num) {this.num = num; }publicString getNom() {returnnom; }public voidsetNom(String nom) {this.nom = nom; }publicString getPrenom() {returnprenom; }public voidsetPrenom(String prenom) {this.prenom = prenom; } } |
La classe PersonneDao
package; importorg.eclipse.model.Personne;importorg.hibernate.Session; public classPersonneDaoextendsGenericDao<Personne, Integer> { publicPersonneDao(Session session) {super(Personne.class, session); } } |
Pour tester tout c¸a dans le main de
packageorg.eclipse; importorg.eclipse.config.HibernateUtil;import.PersonneDao;importorg.eclipse.model.Personne;importorg.hibernate.Session; public classApp {public static voidmain(String[] args)throwsException { Session session = HibernateUtil.getSessionFactory().openSession(); Personne personne =newPersonne(); personne.setNom("Ferdinand"); personne.setPrenom("Rio"); PersonneDao personneDao =newPersonneDao(session);intcle = (personne); .println(cle); Personne personne2 = personneDao.findById(3); personne2.setNom("Turing"); personneDao.saveOrUpdate(personne2); } } |