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.
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.
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.
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); } } }
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.
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.
Téléchargez les .jars de hibernate 4 (le lien de téléchargement est dans la version html) et décompressez-les.
Créer une bibliothèque hibernate4 à l’aide d’eclipse, vous y placerez les fichiers du répertoire /lib/required.
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 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); } } }
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>
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.
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; } }
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); } }
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(); } }
<?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>
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()); } }
L’exemple suivant utilise la base de données suivante :
Les classes permettant l’exploitation de cette base sont représentées ci-dessous :
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); } }
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()); } }
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()); } }
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()); } }
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)); } }
<?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>
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()); } }