Gestion des relations avec JPA

De $1

Introduction

Dans ce TP vous allez rajouter des tables au TP précédent, et commencer à gérer des relations.

Ajout d'une relation 1-N "Adresse"

On suppose qu'une personne peut avoir plusieurs adresses (une adresse professionnelle et une adresse personnelle par exemple, on utilisera pour cela l'attribut "description")

Commençons par créer une classe entité "Adresse" :

@Entity
public class Adresse implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String description;
    private String rue;
    private int codePostal;
    private String ville;       
   ...

On rajoute la relation dans la classe Utilisateur, on a ici une relation 1-N, unidirectionnelle, avec creation et suppression en cascade et chargement agressif :

@Entity
public class Utilisateur implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String firstname;
    private String lastname;
    private String login;
    @OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)          Collection<Adresse> listeDesAdresses;     ...
  • Ajoutez des set/get, modifiez éventuellement le constructeur pour ajouter au moins une adresse par défaut, etc.
  • Modifiez le code du session bean gestionnaire d'utilisateur en conséquence,
  • Modifiez le code qui crée des utilisateurs de test,
  • Modifiez éventuellement la servlet,
  • Modifiez la page JSP pour qu'elle affiche les adresses de chaque utilisateur dans le tableau. N'oubliez pas que l'on peut à l'aide du langage EL écrire ${u.listeDesAdresses.rue}, cela fonctionnera si il existe dans la classe Utilisateur une méthode getListeDesAdresses() et si dans la classe Adresse il existe getRue(). Un attribut qui a des getter/setters s'appelle une propriété. L'opérateur "." du langage EL manipule des propriétés, rien que des propriétés ! Attention, si on était pas en chargement agressif, un utilisateur renvoyé à une JSP pour affichage serait "incomplet", ses adresses n'auraient pas été "remplies" puisque une requête sur un utilisateur ou sur une liste d'utilisateur n'aurait pas déclenché de requête pour charger en mémoire ses adresses. Voir le cours.

Test de l'application modifiée, précautions à prendre

Vous venez de modifier les modèles de données, les tables vont devoir être regénérées. Vérifiez que votre unité de persistence est bien en mode "drop and create" (pour cela, double cliquez sur le fichier persistence.xml dans "configuration").

Déployez ou exécutez le projet, vérifiez que les tables correspondent bien au nouveau modèle que vous avez créé (il doit par exemple y avoir au moins deux tables maintenant, une pour les Utilisateurs et une pour les Adresses)

Ajout d'une relation "Email"  dans la classe Utilisateur

Procédez comme pour les adresses, maitenant on veut ajouter le fait qu'un utilisateur peut avoir plusieurs adresses emails.

Idem : modifiez le code qui créee les utilisateurs de test et ajoutez des adresses emails.

Transformation de la relation Utilisateur-Adresse en relations N-N bi-directionnelle

Maitenant on va modifer le code des entités, de la créations des utilisateurs de test et des interfaces graphiques pour gérer le fait qu'à une certaine adresse plusieurs personnes peuvent habiter (cas d'une famille par exemple). On veut une relation bi-directionnelle cette fois-ci : lister les adresses d'une personne mais aussi les personnes qui habitent à une adresse.

Faites attention au mode de chargement (agressif ou fainéant), etc.

Testez votre application juste avec des utilisateurs et des adresses de test pour commencer. Modifier la JSP pour afficher les adresses et à partir des adresses cliquer sur un lien pour voir les personnes.

Si vous testez la suppression d'un utilisateur, cela ne marchera pas car la relation Utilisateur-Adresse étant en CascadeType.ALL, la destruction d'un utilisateur provoque la destruction des relations vers ses adresses, et comme cela se propage récursivement et que la relation est bi-directionnelle, cela revient à supprimer aussi l'utilisateur -> erreur. Solution :  utiliser à la place un attribut JPA que l'on place dans les annotations de la relation : @OneToMany(... orphanRemoval = true)

Ajout d'une fonctionnalité pour ajouter une nouvelle adresse à une personne

Dans vos pages JSP : ajoutez une interface pour pouvoir ajouter une adresse (postale et email) à une personne :

  • Soit on saisit une nouvelle adresse et elle doit être ajoutée à la base de données (les relations seront mises à jour) et à la liste des adresses de la personne,
  • Soit on peut choisir dans la liste des adresses existantes.