Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Java et Eclipse
  3. Classes entités
Extrait - Java et Eclipse Développez une application avec Java et Eclipse (2e édition)
Extraits du livre
Java et Eclipse Développez une application avec Java et Eclipse (2e édition)
2 avis
Revenir à la page d'achat du livre

Classes entités

Introduction

Il s’agit dans ce chapitre de créer les classes entités ModeReglements, Client, Article et Commande qui représentent le modèle métier principal issu de l’analyse du projet.

Les classes entités ont en majorité des tables correspondantes dans la base de données.

Les entités ont deux versants fonctionnels : l’un décrit les données à manipuler, l’autre décrit les opérations permettant leur interaction avec la base de données.

Ce deuxième aspect concerne principalement les opérations CRUD (Create, Read, Update, Delete, soit Créer, Lire, Modifier, Supprimer) qui permettent respectivement les opérations de création, de lecture, de mise à jour et de suppression des enregistrements de la base de données. L’avancement dans ce chapitre permettra de voir comment les coder au fur et à mesure.

Il est tentant de mélanger les opérations de CRUD à l’intérieur de la classe de données. Cela pose plusieurs soucis : les responsabilités fonctionnelles sont alors mélangées ; le code résultant se retrouve souvent avec des artifices techniques ; l’aspect pédagogique est dilué et l’objectif de ce livre est avant tout pédagogique !

Gestion des erreurs

Une grande partie des activités de développement d’une application est la gestion des erreurs pouvant survenir au cours des activités de cette application.

Concernant l’accès à la base de données, ces erreurs prendront la forme d’exceptions lancées par JPA lorsque les méthodes de la classe EntityManager seront appelées. Ces erreurs héritent de la classe RuntimeException, elles ne font donc pas partie de la signature des méthodes, mais sont quand même susceptibles d’arriver. Plutôt que de les gérer via un bloc try/catch dans cette partie du code, un chapitre ultérieur expliquera comment il reviendra aux méthodes appelantes de les gérer elles-mêmes.

Cette manière de faire simplifie la lisibilité du code, et contribue à une meilleure séparation des tâches : il n’est pas normal pour une classe technique d’afficher des boîtes de dialogue informant d’erreurs !

Gardez à l’esprit que des exceptions peuvent être levées au cours de l’exécution de ces méthodes.

Classe ModeReglements

Commençons par la classe ModeReglements. Il s’agit d’une des plus simples de notre modélisation, et elle est au cœur de l’application. Après tout, il s’agit d’une application de gestion des commandes, et sans règlement cette application ne servirait pas à grand-chose dans une entreprise commerciale !

Voici le code de cette classe, présente dans le package entite :


package entite; 
 
import java.io.Serializable; 
 
import javax.persistence.Basic; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import javax.persistence.Transient;  
 
@Entity 
public class ModeReglements implements Serializable { 
     
    private static final long serialVersionUID = 1L;  
 
    @Id 
    @GeneratedValue 
    private int code;  
     
    @Basic 
    private String type;  
     
    @Transient 
    private transient boolean ignoré; 
     
    /* 
     * Constructeur 1. 
     * Utilisé par JPA. 
     */ 
    public ModeReglements(){ 
        super(); 
    } 
     ...

CRUD de la classe ModeReglements

La classe CRUD du mode de règlement s’appelle ModeReglementsCrud dans ce projet.

 Créez un package crud dans le package entite.

 Créez la classe ModeReglementsCrud dans ce package.


package entite.crud; 
 
import java.util.Collections; 
import java.util.List; 
 
import javax.persistence.EntityManager; 
import javax.persistence.Query; 
import javax.swing.JOptionPane; 
 
import controle.connection.Connexion; 
import entite.ModeReglements; 
 
public class ModeReglementsCrud { 
 
    /** 
     *  
     */ 
    private final Connexion laConnexion; 
 
    /** 
     * Constructeur 
     */ 
    public ModeReglementsCrud(Connexion uneConnexion) { 
        laConnexion = uneConnexion; 
    } 
}
 

Cette classe comporte un constructeur avec un paramètre : l’instance de Connexion. Cela évite de faire appel à des méthodes statiques au cours du cycle de vie de l’application et améliore les possibilités de tests unitaires de cette classe.

Le CRUD doit pouvoir créer, lire, modifier et supprimer une ligne de données. Une possibilité de recherche sera ajoutée à ce corpus de fonctionnalités.

1. Créer

 Créez une nouvelle méthode dans la classe.


/** 
 * Ajout d'un nouvel item dans la base. 
 *  
 * @param type 
 *            le nom textuel du mode de règlement. 
 * @return le mode de règlement créé 
 * ou null si il est impossible de le créer. 
 */ 
public ModeReglements creer(String type) { 
    return laConnexion.modifier((gerant) -> {  
        if ("".equals(type)) { 
           throw new IllegalArgumentException( 
            "Le nom du mode de reglement est obligatoire"); 
        } else {  
           ModeReglements reglements = new ModeReglements(type);
           gerant.persist(reglements); 
    ...

Classe Client

Voici le code de cette classe :


package entite; 
 
import java.io.Serializable; 
import java.time.Instant; 
import java.util.Date; 
 
import javax.persistence.Basic; 
import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.NamedQueries; 
import javax.persistence.NamedQuery; 
import javax.persistence.OneToOne; 
import javax.persistence.Temporal; 
import javax.persistence.TemporalType;  
 
@Entity 
public class Client implements Serializable { 
 
    private static final long serialVersionUID = 1L; 
 
    // Propriétés de base de la classe 
    // ------------------------------- 
    // l'identifiant en base de données  
    @Id 
    private String code; 
 
    @Basic 
    private String nom; 
 
    private String prenom; 
 
    private boolean carte_fidele;  
 
    @Temporal(TemporalType.DATE) 
    private Date date;  
 
    @OneToOne(cascade=CascadeType.ALL) 
    private Adresse adresse; 
 
    // CONSTRUCTEURS 
    // ------------- 
    // 1er constructeur 
    // pour la création complète d'un client 
    // limitée ici à 5 propriétés pour alléger le code 
    public Client(String...

CRUD de la classe Client

Il est maintenant temps de créer la classe d’accès au client.

 Créez la classe ClientCrud dans le package « crud ».


package entite.crud; 
 
import java.util.Collections; 
import java.util.List; 
 
import javax.persistence.EntityManager; 
import javax.persistence.Query; 
import javax.swing.JOptionPane; 
 
import controle.connection.Connexion; 
import entite.Client; 
 
public class ClientCrud { 
 
    // Propriété pour établir la connection avec la BD 
    // ----------------------------------------------- 
    private final Connexion laConnexion; 
 
    // CONSTRUCTEUR 
    // ------------- 
    public ClientCrud(Connexion connexion) { 
        this.laConnexion = connexion; 
    } 
}
 

Le constructeur de cette classe suit le principe de la classe ModeReglementsCrud.

1. Créer

 Créez une nouvelle méthode dans la classe.


// Ajout d'un nouveau client dans la BD 
// ------------------------------------ 
public void creer(Client client) { 
    laConnexion.modifier((gerant) -> {    
        gerant.persist(client); 
        return client; 
    }); 
}
 

À la différence de ModeReglementsCrud, cette méthode prend un client complet en paramètre, et elle ne retourne rien. Si elle se termine normalement, le client a bien été stocké en base. Si l’opération n’a pas pu être finalisée, une exception de type RuntimeException sera lancée par JPA, interrompant le fil normal de l’exécution.

2. Lire

 Créez une nouvelle méthode dans la classe.


/* 
 * Lecture et récupération des enregistrements de la BD 
 */ 
public List<Client> lire() { 
return laConnexion.chercher((gerant) -> { 
        Query query = gerant.createQuery("SELECT c FROM Client c");
        return query.getResultList();   
    }); 
}
 

Cette méthode liste tous les clients stockés dans le système....

Classe Article

Continuons en créant la classe Article dans le package entite.


package entite; 
 
import java.io.Serializable; 
import java.time.Instant; 
import java.util.Date; 
import java.util.HashSet; 
import java.util.Set; 
 
import javax.persistence.Basic; 
import javax.persistence.CascadeType; 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.FetchType; 
import javax.persistence.Id; 
import javax.persistence.ManyToMany; 
import javax.persistence.ManyToOne; 
import javax.persistence.Temporal; 
import javax.persistence.TemporalType;  
 
@Entity 
public class Article implements Serializable { 
 
    private static final long serialVersionUID = 1L; 
 
    @Id 
    private String code;  
 
    @ManyToOne(cascade = { CascadeType.PERSIST }) 
    private Categorie categorie;  
 
    @ManyToMany(fetch = FetchType.EAGER) 
    private Set<Fournisseur> fournisseurs = new HashSet<>(); 
     
    private String designation; 
 
    private int quantite;  
 
    @Column(name="prix_unitaire") 
    private double prixUnitaire; 
 
    @Temporal(TemporalType.DATE) 
    private Date date; 
 
    /* 
     * Constructeur 
     */ 
    public Article(String code, String codeCategorie, 
            String designation, 
            int quantite, double prixUnitaire, 
            Instant date) { 
        this(code,   
                new Categorie().setCode(codeCategorie), 
                designation,  
                quantite, prixUnitaire, ...

CRUD de la classe Article

 Créons maintenant la classe d’accès aux articles.

 Créez une classe ArticleCrud dans le package entite.crud.


package entite.crud; 
 
import java.util.Collections; 
import java.util.List; 
 
import javax.persistence.EntityManager; 
import javax.persistence.Query; 
import javax.swing.JOptionPane; 
 
import controle.connection.Connexion; 
import entite.Article; 
import entite.Categorie; 
 
public class ArticleCrud { 
 
    private final Connexion laConnexion; 
 
    /* 
     * Constructeur 
     */ 
    public ArticleCrud(Connexion connexion) { 
        this.laConnexion = connexion; 
    } 
}
 

1. Créer

 Créez une nouvelle méthode dans la classe.


/** 
 * Ajout d'un nouvel article dans la BD. 
 *  
 * @throws IllegalArgumentException  
 *                 si il est impossible de créer l'article. 
 */ 
public void creer(Article article) { 
    laConnexion.modifier((gerant) -> { 
        gerant.persist(article); 
        return article; 
    }); 
}
 

La nouveauté de cette méthode par rapport aux méthodes créer précédentes est d’indiquer dans la JavaDoc qu’une exception est susceptible d’arriver au cours de son exécution.

images/11-01.png

Il s’agit d’un indicateur supplémentaire pour l’appelant de cette méthode. Néanmoins, cette indication suppose que le développeur lise cette documentation pour en tenir compte !

2. Lire

 Créez deux nouvelles méthodes dans la classe.


/** 
 * Lecture et récupération des enregistrements de la BD. 
 * @throws IllegalArgumentException  ...

Classe Commande

Il est maintenant temps de coder les classes Commande et Ligne : chaque instance de la classe Ligne correspond à une ligne d’achat dans une commande.

 Créez une classe Ligne dans le package entite.


package entite; 
 
import java.io.Serializable; 
 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import javax.persistence.ManyToOne;  
 
@Entity(name="LignesCommandes") 
public class Ligne implements Serializable { 
 
    private static final long serialVersionUID = 1L; 
 
    @Id 
    @GeneratedValue 
    private String id; 
 
    @ManyToOne(optional=false) 
    private Article article; 
 
    private int quantite; 
 
    /* 
     * Constructeur 1 
     */ 
    public Ligne(Article unArticle, int quantite) { 
        this(); 
        this.article = unArticle; 
        this.quantite = quantite; 
    } 
 
    public Ligne() { 
        super(); 
    } 
 
    public Article getArticle() { 
        return article; 
    } 
 
    public void setArticle(Article unArticle) { 
        this.article = unArticle; 
    } 
 
    public int getQuantite() { 
        return quantite; 
    } 
 
    public void setQuantite(int quantite) { 
        this.quantite = quantite; 
    } 
}
 

L’annotation @Entity est paramétrée avec un nom, ce qui permet de changer le nommage par défaut de la table : au lieu de s’appeler LIGNE, elle s’appellera LIGNESCOMMANDES.

L’annotation @ManyToOne est paramétrée avec optional=false, pour lancer une erreur si l’article n’est pas spécifié lors de la sauvegarde.

 Rajoutez les méthodes suivantes dans la classe :


 ...

CRUD de la classe Commande

Créez une classe CommandeCrud dans le package entite.crud.


package entite.crud; 
 
import java.util.Collections; 
import java.util.List; 
 
import javax.persistence.EntityManager; 
import javax.persistence.Query; 
import javax.swing.JOptionPane; 
 
import controle.connection.Connexion; 
import entite.Commande; 
 
public class CommandeCrud { 
 
    private Connexion laConnexion; 
 
    /* 
     * Constructeur 1 
     */ 
    public CommandeCrud(Connexion connexion) { 
        this.laConnexion = connexion; 
    } 
}
 

1. Créer

 Créez une nouvelle méthode dans la classe.


/** 
 * Ajout d'une nouvelle commande dans la BD. 
 * @throws EniException si il est impossible de créer la commande.
 */ 
public void creer(Commande commande) throws EniException {  
    try {             
        laConnexion.modifier((gerant) -> {             
            gerant.persist(commande); 
            return commande; 
        });  
    } catch(RuntimeException e) { 
        throw new EniException(e.getMessage(), e); 
    } 
}
 

Cette méthode a pour particularité de récupérer et transformer l’exception de type RuntimeException, lancée éventuellement par JPA, en une exception spécifique, qui n’est pas de type RuntimeException. Cette dernière doit donc obligatoirement être renseignée dans la signature de la méthode par le mot-clé throws. À partir de là, tout code appelant cette méthode doit explicitement gérer cette exception, faute de quoi le code ne compilera même pas.

Il s’agit d’une technique efficace pour ne pas risquer d’oublier de gérer une erreur éventuelle au cours de l’exécution de l’application.

Il faut néanmoins créer cette exception spécifique.

 Créez une classe EniException dans le package entite.


package entite....

Prise en compte des entités par JPA

Le codage des classes entités et de leurs classes CRUD est presque terminé.

Les classes Categorie et Fournisseur et leurs CRUD associés n’ont pas encore été abordés. Nous vous laissons ce travail à titre d’exercice.

Une fois ces classes codées, il reste à indiquer à JPA que ces classes doivent être prises en compte lors des requêtes vers la base de données.

 Ouvrez le fichier persistence.xml. Vous pouvez utiliser le raccourci [Ctrl][Shift] R pour ouvrir une boîte de dialogue de recherche rapide. Commencez à taper le nom du fichier dans la zone de recherche. L’espace de travail sera scanné afin d’afficher les fichiers correspondants. Double cliquez sur le fichier voulu.

images/9-11-1.png

 Modifiez le fichier en y insérant des éléments XML class :

images/11-04.png

 Sauvegardez le fichier en tapant [Ctrl] S.