pdf - e-book - archive - github.com

1.18  Hibernate

1.18.1  Introduction

Dès que l’on souhaite manier des données persistantes dans un contexte autorisant les connexions simultanées, l’utilisation d’une base de données est incontournable.

Les Data Access Objects

Un DAO (Data Access Objects) est un objet rendu persistant par une base de données, ou permettant de rendre un objet persistant.

La programmation des DAO (Data Access Objects) à l’aide de JDBC oblige le programmeur à mettre au point un code long et répétitif. Ce qui, en plus de nécessiter un code pénible (et difficile) à rédiger, est une source d’erreurs non négligeable.

Les ORM

Un package d’ORM (Object/Relationnal Mapping) permet de sous-traiter la persistance des données. Il devient alors possible d’enregistrer ou de lire des objets dans une base de données en quelques instructions.

L’utilisation de ce type de bibliothèque occasionne un gain considérable de temps tout en garantissant un programme bien plus fiable. Hibernate est la bibliothèque qui sera présentée dans ce cours, mais les concepts (et même la syntaxe des annotations) que nous passerons en revue sont facilement transposable à un autre outil, voire à un autre langage.

La norme JPA

Hibernate utilise des annotations, c’est à dire des indications qui se placent dans les fichiers sources. Les annotations ne sont pas exécutées par le compilateur, mais sont utilisées par d’autres programmes (documenteur, ORM, etc.). Par exemple :

package hibernate.premierExemple;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

@Entity
@Table(name = "personne")
class Personne
{
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = "num")
 private int num;

 @Column(name = "nom")
 private String nom;

 @Column(name = "prenom")
 private String prenom;

 public Personne(String prenom, String nom)
 {
  this.nom = nom;
  this.prenom = prenom;
 }
}

public class PremierExemple
{
 private static Session getSession() throws HibernateException
 {
  Configuration configuration = new Configuration()
    .configure("hibernate/premierExemple/PremierExemple.cfg.xml");
  ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
    .applySettings(configuration.getProperties()).build();
  SessionFactory sessionFactory = configuration
    .buildSessionFactory(serviceRegistry);
  return sessionFactory.openSession();
 }

 public static void main(String[] args)
 {
  try
  {
   Session s = getSession();
   Personne joffrey = new Personne("Joffrey", "Baratheon");
   Transaction t = s.beginTransaction();
   s.persist(joffrey);
   t.commit();
   s.close();
  }
  catch (HibernateException ex)
  {
   throw new RuntimeException("Probleme de configuration : "
     + ex.getMessage(), ex);
  }
 }
}

Télécharger le fichier

L’annotation ci-dessus est lue par Hibernate et lui indique comment représenter le champ nom dans une base de données relationnelle. Les annotations permettant de gérer la persistance des données répondent à la norme JPA (Java Persistence Annotations) et sont donc les mêmes d’un ORM à l’autre.

Avant de présenter les nombreuse facettes d’hibernate, je vous propose de commencer par un exemple.

1.18.2  Un premier exemple

Cet exemple, un des plus épurés qu’il est possible de faire, permet de rendre persistant dans une table appelée personne des objets contenant les trois champs num, nom, et prénom. Il ne sera pas nécessaire de créer la base de données, Hibernate se chargera tout seul de créer les tables. Suivez scrupuleusement les indications ci-dessous pour exécuter le programme, vous aurez ensuite droit aux explications.

Bibliothèque

Téléchargez les .jars de hibernate 4 (le lien de téléchargement est dans la version html) et décompressez-les.

Site d’hibernate

Créer une bibliothèque hibernate4 à l’aide d’eclipse, vous y placerez les fichiers du répertoire /lib/required.

Base de données

Créez, sous mysql, la base de données que l’on utilisera avec les instructions suivantes :

create database courshibernate;

Attention à bien respectez les noms et la casse, sinon le programme ne fonctionnera pas. L’instruction suivante permet de créer un compte :

grant all privileges on courshibernate.* to 'hibernate'@'localhost' identified by 'hibernate';

Prenez note du fait que le nom de la base de données est courshibernate, celle de l’utilisateur est hibernate, et le password est hibernate. Faites attention au fait que si les identifiants ne correspondent pas à ceux que j’ai utilisés, le programme ne fonctionnera pas.

Le fichier java

Le fichier suivant, dont je vous déconseille de changer le nom, est à placer dans src/hibernate/PremierExemple/. Il s’agit du code source contenant la classe à mapper ainsi que les appels à Hibernate.

package hibernate.premierExemple;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

@Entity
@Table(name = "personne")
class Personne
{
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = "num")
 private int num;

 @Column(name = "nom")
 private String nom;

 @Column(name = "prenom")
 private String prenom;

 public Personne(String prenom, String nom)
 {
  this.nom = nom;
  this.prenom = prenom;
 }
}

public class PremierExemple
{
 private static Session getSession() throws HibernateException
 {
  Configuration configuration = new Configuration()
    .configure("hibernate/premierExemple/PremierExemple.cfg.xml");
  ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
    .applySettings(configuration.getProperties()).build();
  SessionFactory sessionFactory = configuration
    .buildSessionFactory(serviceRegistry);
  return sessionFactory.openSession();
 }

 public static void main(String[] args)
 {
  try
  {
   Session s = getSession();
   Personne joffrey = new Personne("Joffrey", "Baratheon");
   Transaction t = s.beginTransaction();
   s.persist(joffrey);
   t.commit();
   s.close();
  }
  catch (HibernateException ex)
  {
   throw new RuntimeException("Probleme de configuration : "
     + ex.getMessage(), ex);
  }
 }
}

Télécharger le fichier

Le fichier de configuration

Le fichier suivant est à placer dans src/. Il contient les identifiants de connexion à la base de données ainsi que les noms des classes qui seront mappées.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration
    PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory >

 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 <property name="hibernate.connection.url">
     jdbc:mysql://localhost/hibernate
 </property>
 <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
 <property name="hibernate.connection.username">hibernate</property>
 <property name="hibernate.connection.password">hibernate</property>
 <property name="hibernate.show_sql">true</property>
   
 <property name="hbm2ddl.auto">create</property>
 
 <mapping class="hibernate.premierExemple.Personne" />
         
</session-factory>
</hibernate-configuration>

Télécharger le fichier

Lancement sous Eclipse

Une fois tous les fichiers placés, il convient d’ajouter la librairie Hibernate précédemment crée au Build path pour que le fichier source puisse compiler. Lorsque vous lancerez l’exécution, un log (en rouge) sera généré et se terminera par l’affichage d’une requête. Si une exception est levée, c’est qu’un fichier a été mal placé ou mal orthographié.

Vous pourrez constater que le programme a fonctionné en consultant la base de données : la table personne a été crée et une personne a été insérée.

1.18.3  Un gestionnaire de contacts en quelques lignes

Le fichier métier

package hibernate.gestionContacts;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
class Contact
{
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private int num;

 private String nom;

 private String prenom;

 Contact()
 {
 }

 public Contact(String prenom, String nom)
 {
  this.nom = nom;
  this.prenom = prenom;
 }

 int getNum()
 {
  return num;
 }

 void setNum(int num)
 {
  this.num = num;
 }

 public String getNom()
 {
  return nom;
 }

 public void setNom(String nom)
 {
  this.nom = nom;
 }

 public String getPrenom()
 {
  return prenom;
 }

 public void setPrenom(String prenom)
 {
  this.prenom = prenom;
 }

 @Override
 public String toString()
 {
  return prenom + " " + nom;
 }
}

Télécharger le fichier

Le point d’entrée

package hibernate.gestionContacts;

import java.util.List;

public class GestionContacts
{
 private static GestionContacts gestionContacts = null;
 
 public List<Contact> getContacts()
 {
  return Passerelle.refreshList();  
 }
 
 public static GestionContacts getGestionContacts()
 {
  if (gestionContacts == null)
   gestionContacts = new GestionContacts();
  return gestionContacts;
 }
 
 private GestionContacts(){}
 
 public void sauvegarder(Contact contact)
 {
  Passerelle.save(contact);
 }

 public void supprimer(Contact contact)
 {
  Passerelle.delete(contact);
 }
}

Télécharger le fichier

La passerelle

package hibernate.gestionContacts;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

abstract class Passerelle
{
 private static Session session = null;

 static
 {
  SessionFactory sessionFactory = null;
  try
  {
   Configuration configuration = new Configuration()
     .configure("hibernate/gestionContacts/GestionContacts.cfg.xml");
   ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
     .applySettings(configuration.getProperties()).build();
   sessionFactory = configuration.buildSessionFactory(serviceRegistry);
   session = sessionFactory.openSession();
  }
  catch (HibernateException ex)
  {
   throw new RuntimeException("Probleme de configuration : "
     + ex.getMessage(), ex);
  }
 }

 static void delete(Contact personne)
 {
  Transaction tx = session.beginTransaction();
  session.delete(personne);
  tx.commit();
 }

 static void save(Contact personne)
 {
  Transaction tx = session.beginTransaction();
  session.save(personne);
  tx.commit();
 }

 @SuppressWarnings("unchecked")
 static java.util.List<Contact> refreshList()
 {
  Query query = session.createQuery("from Contact");
  return query.list();
 }
}

Télécharger le fichier

Le fichier de configuration

<?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 >

  <!-- local connection properties -->
     <property name="hibernate.dialect">
      org.hibernate.dialect.MySQLDialect</property>
  <property name="hibernate.connection.url">
   jdbc:mysql://localhost/hibernate</property>
  <property name="hibernate.connection.driver_class">
   com.mysql.jdbc.Driver</property>
  <property name="hibernate.connection.username">
   hibernate</property>
  <property name="hibernate.connection.password">
   hibernate</property>

    <property name="hbm2ddl.auto">update</property>

        <!-- property name="hibernate.show_sql">true</property -->
        <property name="hibernate.use_outer_join">true</property>
        <property name="jta.UserTransaction">
         java:comp/UserTransaction</property>
         <mapping class="hibernate.gestionContacts.Contact" />
         
    </session-factory>
</hibernate-configuration>

Télécharger le fichier

Les entrées/sorties

package hibernate.gestionContacts;

import commandLineMenus.List;
import commandLineMenus.Menu;
import commandLineMenus.Option;
import commandLineMenus.rendering.examples.util.InOut;

public class GestionContactsLigneCommande
{
 GestionContacts gestionContacts;
 
 public GestionContactsLigneCommande(GestionContacts gestionContacts)
 {
  this.gestionContacts = gestionContacts;
  menuPrincipal().start();
 }
 
 private Option getAfficher()
 {
  return new Option("Afficher", "l", 
    () -> 
    {
     for (Contact contact : gestionContacts.getContacts())
      System.out.println(contact);
    }
   );
 }

 private Option getAjouter()
 {
  return new Option("Ajouter", "a", 
    () -> 
    {
     gestionContacts.sauvegarder(new Contact(
       InOut.getString("Prénom : "), 
       InOut.getString("Nom : ")));
    }
   );
 }

 private Option getSupprimer()
 {
  return new List<>("Supprimer", "s",
    () -> gestionContacts.getContacts(),
    (indice, contact) -> 
     {
      gestionContacts.supprimer(contact);
     }
    );
 }

 private Option getModifier()
 {
  return new List<>("Modifier", "m",
    () -> gestionContacts.getContacts(),
    (indice, contact) -> 
     {
      contact.setPrenom(InOut.getString("Prénom : "));
      contact.setNom(InOut.getString("Nom : "));
      gestionContacts.sauvegarder(contact);
     }
    );
 }

 private Menu menuPrincipal()
 {
  Menu menu = new Menu("Gestionnaire de contacts");
  menu.add(getAfficher());
  menu.add(getAjouter());
  menu.add(getSupprimer());
  menu.add(getModifier());
  menu.addQuit("q");
  return menu;
 }

 public static void main(String[] args)
 {
  new GestionContactsLigneCommande(GestionContacts.getGestionContacts());
 }
}

Télécharger le fichier

1.18.4  Un exemple de relations entre les classes

L’exemple suivant utilise la base de données suivante :

Les classes permettant l’exploitation de cette base sont représentées ci-dessous :

La couche métier

package hibernate.relations;

import java.util.Collections;
import java.util.TreeSet;
import java.util.SortedSet;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.SortNatural;

@Entity
public class Client
{
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private int num;

 private String nom;

 @OneToMany(mappedBy = "client")
 @Cascade(value = { CascadeType.ALL })
 @SortNatural
 private SortedSet<Commande> commandes = new TreeSet<>();

 @SuppressWarnings("unused")
 private Client()
 {
 }

 public Client(String nom)
 {
  this.nom = nom;
 }

 public String getNom()
 {
  return nom;
 }

 int getNum()
 {
  return num;
 }
 
 public void delete()
 {
  Passerelle.delete(this);
 }

 public void save()
 {
  Passerelle.save(this);
 }

 @Override
 public String toString()
 {
  return nom + "(" + getCommandes().size() + " commande(s))";
 }

 public Commande createCommande()
 {
  Commande commande = new Commande(this);
  commandes.add(commande);
  return commande;
 }

 void remove(Commande commande)
 {
  commandes.remove(commande);
 }

 public SortedSet<Commande> getCommandes()
 {
  return Collections.unmodifiableSortedSet(commandes);
 }
}

Télécharger le fichier

package hibernate.relations;

import java.util.Date;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;

import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.SortNatural;

@Entity
public class Commande implements Comparable<Commande>
{
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private int num;

 private Date date;

 @ManyToOne
 @Cascade(value = { CascadeType.SAVE_UPDATE})
 private Client client;

 @OneToMany(mappedBy = "commande")
 @Cascade(value = { CascadeType.ALL })
 @SortNatural
 @MapKey(name = "produit")
 private SortedMap<Produit, DetailCommande> detailsCommandes = new TreeMap<>();

 @SuppressWarnings("unused")
 private Commande()
 {
 }

 Commande(Client client)
 {
  this.date = new Date();
  this.client = client;
 }

 int getNum()
 {
  return num;
 }
 
 public Client getClient()
 {
  return client;
 }

 public Date getDate()
 {
  return date;
 }

 public void delete()
 {
  client.remove(this);
  Passerelle.delete(this);
 }

 public void save()
 {
  Passerelle.save(this);
 }

 public void add(Produit produit, int quantite)
 {
  detailsCommandes.put(produit, new DetailCommande(this, produit,
    quantite));
 }

 public void remove(Produit produit)
 {
  detailsCommandes.remove(produit);
 }

 public SortedSet<Produit> getProduits()
 {
  return new TreeSet<Produit>(detailsCommandes.keySet());
 }

 SortedSet<DetailCommande> getDetailsCommande()
 {
  return new TreeSet<DetailCommande>(detailsCommandes.values());
 }

 public int getNbProduits()
 {
  return detailsCommandes.size();
 }

 public int getQuantite(Produit produit)
 {
  return detailsCommandes.get(produit).getQuantite();
 }

 @Override
 public String toString()
 {
  String s = client.getNom() + "::" + num + " ";
  for (DetailCommande detailCommande : detailsCommandes.values())
   s += detailCommande + " -> ";
  s += "\n";
  return s;
 }

 @Override
 public int compareTo(Commande autre)
 {
  return getDate().compareTo(autre.getDate());
 }
}

Télécharger le fichier

package hibernate.relations;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

@Entity
public class Produit implements Comparable<Produit>
{
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private int num;

 private String nom;

 private double prix;

 @OneToMany(mappedBy = "produit", orphanRemoval=true)
 @Cascade(value = { CascadeType.ALL })
 private Set<DetailCommande> detailsCommandes = new HashSet<>();

 void add(DetailCommande detailCommande)
 {
  detailsCommandes.add(detailCommande);
 }

 void remove(DetailCommande detailCommande)
 {
  detailsCommandes.remove(detailCommande);
 }

 public int getNbCommandes()
 {
  return detailsCommandes.size();
 }

 @SuppressWarnings("unused")
 private Produit()
 {
 }

 public Produit(String nom, double prix)
 {
  this.nom = nom;
  this.prix = prix;
 }
 
 int getNum()
 {
  return num;
 }

 public String getNom()
 {
  return nom;
 }

 public double getPrix()
 {
  return prix;
 }

 public void delete()
 {
  for (DetailCommande detailCommande : detailsCommandes)
   detailCommande.delete();
  Passerelle.delete(this);
 }

 public void save()
 {
  Passerelle.save(this);
 }

 @Override
 public String toString()
 {
  return nom + "(" + prix + " euros)";
 }

 @Override
 public int compareTo(Produit autre)
 {
  return getNom().compareTo(autre.getNom());
 }
}

Télécharger le fichier

package hibernate.relations;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

@Entity
class DetailCommande implements Comparable<DetailCommande>
{
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private int num;

 @ManyToOne
 @Cascade(value = { CascadeType.ALL })
 private Commande commande;

 @ManyToOne
 @Cascade(value = { CascadeType.ALL })
 private Produit produit;

 private int quantite;

 @SuppressWarnings("unused")
 private DetailCommande()
 {
 }

 DetailCommande(Commande commande, Produit produit, int quantite)
 {
  this.commande = commande;
  this.produit = produit;
  produit.add(this);
  this.quantite = quantite;
 }

 int getQuantite()
 {
  return quantite;
 }

 Commande getCommande()
 {
  return commande;
 }

 Produit getProduit()
 {
  return produit;
 }

 @Override
 public String toString()
 {
  return "" + quantite + " * " + produit.getNom();
 }

 void delete()
 {
  if (commande != null)
  {
   Commande commande = this.commande;
   this.commande = null;
   commande.remove(this.getProduit());
  }
  if (produit != null)
  {
   Produit produit = this.produit;
   this.produit = null;
   produit.remove(this);
  }
  Passerelle.delete(this);
 }

 @Override
 public int compareTo(DetailCommande autre)
 {
  return this.getProduit().compareTo(autre.getProduit());
 }
}

Télécharger le fichier

La passerelle

package hibernate.relations;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

class Passerelle
{
 private static Session session = null;
 private static SessionFactory sessionFactory = null;
 private static final String CONF_FILE = "hibernate/relations/relations.cfg.xml";
 private static Transaction transaction = null;
 
 static void initHibernate()
 {
  try
  {
   Configuration configuration = new Configuration()
     .configure(CONF_FILE);
   ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
     .applySettings(configuration.getProperties()).build();
   sessionFactory = configuration.buildSessionFactory(serviceRegistry);
  }
  catch (HibernateException ex)
  {
   throw new RuntimeException("Probleme de configuration : "
     + ex.getMessage(), ex);
  }  
 }
 
 public static void open()
 {
  if (sessionFactory == null)
   initHibernate();
  if (!isOpened())
   session = sessionFactory.openSession();
 }

 public static boolean isOpened()
 {
  return session != null && session.isOpen();
 }
 
 public static void close()
 {
  if (isOpened())
   session.close();
 }

 static void delete(Object o)
 {
  transaction = session.beginTransaction();
  session.delete(o);
  transaction.commit();
  transaction = null;
  session.flush();
 }

 static void save(Object o)
 {
  Transaction tx = session.beginTransaction();
  session.save(o);
  tx.commit();
  session.flush();
 }

 @SuppressWarnings("unchecked")
 public static <T> List<T> getData(String className)
 {
  Query query = session.createQuery("from " + className);
  return new ArrayList<T>((List<T>) query.list());
 }

 @SuppressWarnings("unchecked")
 public static <T> T getData(String className, int id)
 {
  Query query = session.createQuery("from " + className + " where num = "
    + id);
  return (T) (query.list().get(0));
 }
}

Télécharger le fichier

Le fichier de configuration

<?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 >

  <!-- local connection properties -->
     <property name="hibernate.dialect">
      org.hibernate.dialect.MySQLDialect</property>
  <property name="hibernate.connection.url">
   jdbc:mysql://localhost/hibernate_relations</property>
  <property name="hibernate.connection.driver_class">
   com.mysql.jdbc.Driver</property>
  <property name="hibernate.connection.username">
   hibernate</property>
  <property name="hibernate.connection.password">
   hibernate</property>

    <!-- Comportement pour la conservation des tables -->
    <property name="hbm2ddl.auto">create</property>

        <property name="hibernate.show_sql">false</property>
        <property name="jta.UserTransaction">
         java:comp/UserTransaction</property>
        <mapping class="hibernate.relations.Client" />
        <mapping class="hibernate.relations.Commande" />
        <mapping class="hibernate.relations.Produit" />
        <mapping class="hibernate.relations.DetailCommande" />
         
    </session-factory>
</hibernate-configuration>

Télécharger le fichier

Le fichier de test

Une configuration d’hibernate est laborieuse et difficile à tester. L’usage de tests unitaires permet un gain de temps et de fiabilité non négligeable (Téléchargeable seulement depuis la version web du cours).

package hibernate.relations;

import static hibernate.relations.Passerelle.*;
import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestRelations
{
 private Client joffrey;
 private Commande commandeJoffrey;
 private Produit arbalete;
 
 @Before
 public void setUp() throws Exception
 {
  open();
 }

 @After
 public void tearDown() throws Exception
 {
  deleteCommandeJoffrey();
  deleteJoffrey();
  deleteArbalete();
  close();
 }

 private void reopen() throws RuntimeException
 {
  close();
  open();
 }

 private int count(String className)
 {
  return getData(className).size();
 }
 
 private void createJoffrey()
 {
  if (joffrey == null)
  {
   joffrey = new Client("Joffrey");
   assertEquals(0, joffrey.getNum());
   joffrey.save();
  }
 }
 
 private void deleteJoffrey()
 {
  if (joffrey != null)
  {
   joffrey.delete();
   assertNotEquals(0, joffrey.getNum());
   assertNotEquals(0, joffrey.getNum());
   joffrey = null;
  }
  reopen();
  assertEquals(0, count("Client"));
  assertEquals(0, count("Commande"));
 }

 private void createCommandeJoffrey()
 {
  createJoffrey();
  commandeJoffrey = joffrey.createCommande();
  commandeJoffrey.save();
  assertEquals(joffrey, commandeJoffrey.getClient());
 }
 
 private void deleteCommandeJoffrey()
 {
  if (commandeJoffrey != null)
  {
   assertEquals(1, count("Client"));
   commandeJoffrey.delete();
   commandeJoffrey = null;
   assertEquals(1, count("Client"));
  }
  assertEquals(0, count("Commande"));
 }

 private void createArbalete()
 {
  arbalete = new Produit("Arbalète", 12);
  assertEquals(0, arbalete.getNum());
  arbalete.save();
 }
 
 private void deleteArbalete()
 {
  if (arbalete != null)
  {
   arbalete.delete();
   assertNotEquals(0, arbalete.getNum());
   arbalete = null;
  }
  assertEquals(0, count("Produit"));
 }

 @Test
 public void testCreateDeleteClient() throws Exception
 {
  createJoffrey();
  assertEquals(joffrey.getNom(), "Joffrey");
  int id = joffrey.getNum();
  assertNotEquals(0, id);
  assertEquals(joffrey, getData("Client", id));
  reopen();
  joffrey = getData("Client", id);
  assertEquals("Joffrey", joffrey.getNom());
  assertEquals(1, count("Client"));
  deleteJoffrey();
  assertEquals(0, count("Client"));
 }
 
 @Test
 public void testCreateDeleteCommande() throws Exception
 {
  createCommandeJoffrey();
  int id = joffrey.getNum();
  reopen();
  assertEquals(1, count("Commande"));
  joffrey = getData("Client", id);
  assertEquals(1, joffrey.getCommandes().size());
  commandeJoffrey = joffrey.getCommandes().first();
  deleteCommandeJoffrey();
  assertEquals(0, joffrey.getCommandes().size());
 }

 @Test
 public void testInsertionClientCascade() throws Exception
 {
  Client cersei = new Client("Cersei");
  Commande commandeCersei = cersei.createCommande();
  assertEquals(0, count("Commande"));
  assertEquals(0, cersei.getNum());
  commandeCersei.save();
  int id = cersei.getNum();
  assertNotEquals(id, 0);
  assertEquals(1, count("Client"));
  assertEquals(1, count("Commande"));
  assertEquals(cersei, getData("Client", id));
  assertEquals(commandeCersei, getData("Commande", commandeCersei.getNum()));
  reopen();
  assertEquals(1, count("Client"));
  assertEquals(1, count("Commande"));
  cersei = ((Client) getData("Client", id));
  assertEquals("Cersei", cersei.getNom());
  cersei.delete();
  assertEquals(0, count("Client"));
  assertEquals(0, count("Commande"));
  reopen();
  assertEquals(0, count("Client"));
  assertEquals(0, count("Commande"));
 }

 @Test
 public void testCreateDeleteProduit() throws Exception
 {
  createArbalete();
  int id = arbalete.getNum();
  assertNotEquals(id, 0);
  assertEquals(count("Produit"), 1);
  assertEquals(arbalete, getData("Produit", id));
  reopen();
  assertEquals(count("Produit"), 1);
  arbalete = getData("Produit", id);
  assertEquals(arbalete.getNom(), "Arbalète");
  assertEquals(arbalete.getPrix(), 12, 0);
  deleteArbalete();
  assertEquals(count("Produit"), 0);
 }

 @Test
 public void testAddRemoveProduitCommande() throws Exception
 {
  createJoffrey();
  createArbalete();
  createCommandeJoffrey();
  int id = joffrey.getNum();
  commandeJoffrey.add(arbalete, 2);
  assertEquals(1, commandeJoffrey.getDetailsCommande().size());
  commandeJoffrey.save();
  reopen();
  joffrey = getData("Client", id);
  commandeJoffrey = joffrey.getCommandes().first();
  assertEquals(1, commandeJoffrey.getDetailsCommande().size());
  arbalete = commandeJoffrey.getProduits().first();
  assertEquals(2, commandeJoffrey.getQuantite(arbalete));
  Produit hachoir = new Produit("Hachoir", 5);
  commandeJoffrey.add(hachoir, 3);
  commandeJoffrey.save();
  assertEquals(2, count("Produit"));
  assertEquals(2, commandeJoffrey.getDetailsCommande().size());
  commandeJoffrey.remove(hachoir);
  assertEquals(2, count("Produit"));
  assertEquals(1, commandeJoffrey.getDetailsCommande().size());
  hachoir.delete();
  deleteArbalete();
  assertEquals(0, count("Produit"));
  assertEquals(0, commandeJoffrey.getDetailsCommande().size());
 }

}

Télécharger le fichier