4. Enregistrement d'une Map

Les tables de hachage sont supportées par JPA, en tant que collections d'éléments (donc comme des collections de types de base), ou relations vers des entités. Chaque champ de type Map doit donc être annoté soit par @ElementCollection si les valeurs de cette table sont des types de base, soit par @OneToMany ou @ManyToMany si ce sont des entités. La clé de cette table de hachage peut être un type de base. Dans ce cas, on peut annoter la Map avec @MapKeyColumn, ce qui permet de préciser les paramètres de la colonne qui portera cette clé, entre autres son nom. Si cette clé est une entité, alors une jointure sera utilisée pour retrouver cette entité. Dans ce cas, on peut préciser les paramètres de la colonne de jointure en utilisant l'annotation @MapKeyJoinColumn. Enfin, les valeurs de cette table de hachage peuvent être des types de base. Dans ce cas, notre Map doit être annotée par @ElementCollection. S'il s'agit d'entités, alors l'annotation doit être @OneToMany ou @ManyToMany.

4.1. Table de hachage de type (type de base, entité)

Ces tables de hachage sont des relations qui peuvent être de type 1:p ou n:p, donc annotées par @OneToMany ou @ManyToMany. Tout ce qui a été vu sur ces relations s'applique ici, notamment la présence ou non d'une table de jointure. Voyons un exemple d'une table de hachage dont les clés sont des types de base, et les valeurs des entités.

Exemple 24. Table de hachage (type de base, entité)

// 
 // Entité Departement
 //
 @Entity
 public  class Departement  implements Serializable {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     @OneToMany(mappedBy="departement")
     @MapKeyColumn(name="commune_key")
     private Map<String, Commune> communeByName ;
    
     // suite de la classe 
}

 // 
 // Entité Commune
 //
 @Entity
 public  class Commune  implements Serializable {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     @ManyToOne
     private Departement departement ;

     private String name ;
    
     // suite de la classe
}

Nous avons une relation bidirectionnelle @OneToMany classique, dans laquelle l'entité maître est Commune. Examinons le schéma généré par JPA.
Schéma pour une table de hachage (type de base, entité)

Figure 20. Schéma pour une table de hachage (type de base, entité)


Comme il a déjà été montré, l'entité maître Commune porte la table de jointure. S'ajoute la colonne commune_key, conformément à ce que nous avons spécifié par l'annotation @MapKeyColumn. Cette colonne est de même type que la clé, et porte directement la valeur de cette clé.

4.2. Cas où la clé est un champ de la valeur

Ce cas est le cas nominal de JPA 1.0. La table de hachage que l'on gère est de type (type de base, entité), et la clé de chaque colonne correspond à un champ particulier de l'entité valeur.

Exemple 25. Table où la clé est un champ de la valeur

//
 // Entité Departement
 //
 @Entity
 public  class Departement  implements Serializable {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     @OneToMany
     @MapKey(name="name")  // ce champ est le champ name de la classe Commune
     private Map<String, Commune> communeByName ;
    
     // reste de la classe
}

 //
 // Entité Commune
 //
 @Entity
 public  class Commune  implements Serializable {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     private String name ;
    
     // reste de la classe
}

Notre exemple comporte deux entités : Departement et Commune. L'entité Departement possède une table de hachage qui lui permet d'obtenir les objets commune à partir de leurs noms. Cette table est une relation @OneToMany, unidirectionnelle, qui créera donc une table de jointure. L'annotation @MapKey sur cette table de hachage indique à JPA que c'est le champ name de l'entité valeur de cette table qui est utilisée comme clé. Ce champ n'est pas nécessairement la clé primaire de l'entité valeur (ici Commune), cela dit il vaut mieux qu'il y ait une contrainte d'unicité dessus. La structure de table créée par JPA dans ce cas est la suivante. On remarque que la clé est stockée dans la table de jointure (colonne CommuneByName_Key). Si l'on avait choisi comme valeur la clé primaire de l'entité Commune, alors il n'y aurait pas eu besoin de cette colonne supplémentaire.
Schéma pour une table où la clé est un champ de la valeur

Figure 21. Schéma pour une table où la clé est un champ de la valeur


On remarque que ce schéma comporte une table de jointure, ce qui était prévu. Cette table de jointure porte deux colonnes : la première est une clé étrangère vers la clé primaire de Maire, l'autre vers la clé primaire de Departement. Nous sommes bien dans le cadre d'une relation 1:p unidirectionnelle avec table de jointure classique.

4.3. Cas d'une table (entité, entité)

Une nouveauté de JPA 2.0 est le support de ce type de table. Pour construire un exemple nous avons besoin de trois entités : une qui porte la relation, une deuxième pour porter la clé de notre table, et une troisième qui porte la valeur. Construisons cet exemple.

Exemple 26. Table de hachage (entité, entité)

//
 // Entité Departement
 //
 @Entity
 public  class Departement  implements Serializable {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     @ManyToMany
     private Map<Maire, Commune> communeByMaire ;
    
     // reste de la classe
}

 // 
 // Entité Maire
 //
 @Entity
 public  class Maire  implements Serializable {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     private String nom ;
    
     // reste de la classe
}

 //
 // Entité Commune
 //
 @Entity
 public  class Commune  implements Serializable {

     private  static  final  long serialVersionUID =  1L ;

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     private String name ;
    
     // reste de la classe
}

Examinons à présent le schéma généré par JPA.
Schéma pour une table de hachage (entité, entité)

Figure 22. Schéma pour une table de hachage (entité, entité)


JPA a créé une table de jointure entre la table departement et la table commune. Ce point est attendu, dans la mesure où notre relation est définie entre deux entités associées à ces tables. La table de jointure définit deux clés étrangères, l'une vers commune, l'autre vers departement, ce qui est également le comportement nominal dans ce cas. Une colonne supplémentaire est créée, qui porte une clé étrangère vers la clé primaire de l'entité qui sert de clé à cette table, ici CommuneByMaire_Key. Ce mécanisme va permettre de récupérer des communes à partir de leur maire, comme on le souhaite dans cette relation.
JPA & EJB
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
Introduction
1. Objet du mapping objet / relationnel
2. Un peu d'histoire
Un premier exemple
1. Introduction
2. Création de l'environnement technique
2.1. Introduction
2.2. Création de la base Derby
2.3. Création du projet NetBeans et d'une première entité
2.4. Structure d'un projet persistant
2.5. Une première classe persistante
2.6. Un premier fichier persistence.xml
3. Utilisation de ce premier exemple
3.1. Écriture du code d'utilisation
3.2. Exécution de notre premier exemple
3.3. Modification de la class Marin
3.4. Opérations CRUD
Mettre un jeu de classes en base
1. Introduction
2. Définition d'une entité JPA
2.1. Écriture de l'entité
2.2. Annotation de l'entité
2.3. Annotations des champs
2.4. Exemple d'utilisation
3. Opérations sur les entités
3.1. Introduction
3.2. Opération PERSIST
3.3. Opération REMOVE
3.4. Opération REFRESH
3.5. Opération DETACH
3.6. Opération MERGE
4. Mise en relation d'entités
4.1. Introduction
4.2. Relations unidirectionnelles et bidirectionnelles
4.3. Relation 1:1
4.4. Relation 1:p
4.5. Relation p:1
4.6. Relation n:p
4.7. Comportement cascade
4.8. Effacement des entités orphelines
5. Charger des entités et leurs relations
6. Objets inclus
6.1. Introduction
6.2. Déclaration d'un objet inclus
6.3. Utilisation d'objets inclus
6.4. Cas où l'objet inclus est nul
6.5. Renommer les colonnes incluses
6.6. Collections d'objets inclus
L'API Collection en base
1. Introduction
2. Enregistrer une collection d'entités
2.1. Enregistrement d'une collection simple
2.2. Enregistrement d'un Set
2.3. Enregistrement d'une List
3. Enregistrer une collection de types de base
4. Enregistrement d'une Map
4.1. Table de hachage de type (type de base, entité)
4.2. Cas où la clé est un champ de la valeur
4.3. Cas d'une table (entité, entité)
Héritage
1. Introduction
2. Enregistrement d'une hiérarchie de classes
2.1. Entité et super-classe non enregistrée
2.2. Position du problème
2.3. Trois façons de faire
3. Stratégie SINGLE_TABLE
3.1. Fonctionnement
3.2. Mise en place
3.3. Limitations
4. Stratégie JOINED
4.1. Fonctionnement
4.2. Mise en place
4.3. Limitations
5. Stratégie TABLE_PER_CLASS
5.1. Fonctionnement
5.2. Mise en place
5.3. Limitations
Requêtes
1. Introduction
2. Un premier exemple
2.1. Écriture d'une première requête
2.2. Exécution d'une première requête
2.3. Exécution d'une première requête d'agrégation
3. Définition de requêtes
3.1. Requêtes dynamiques
3.2. Requêtes paramétrées
3.3. Requêtes nommées
3.4. Requêtes natives
4. Exécution, analyse du résultat
4.1. Exécution d'une requête dynamique
4.2. Exécution d'une requête nommée
4.3. Analyse du résultat
4.4. Cas des résultats de grande taille
4.5. Remarques
5. Clause From
5.1. Définition des entités
5.2. Jointures dans la clause From
5.3. Remarque finale sur les jointures en JPQL
6. Clause Where
6.1. Variables et chemins dans une clause where
6.2. Expressions conditionnelles et opérateurs
6.3. Requêtes imbriquées
6.4. Opérateurs any, all et some
6.5. Expressions fonctionnelles
7. Clauses Group By et Having
8. Opérations Update et Delete
EJB
1. Introduction
2. Un premier exemple
2.1. Introduction
2.2. Installation dans Glassfish à l'aide de Netbeans
2.3. Création d'un premier EJB
2.4. Déploiement de notre premier EJB
2.5. Création d'un client
3. Mise en oeuvre du pattern session facade
3.1. Introduction
3.2. Modèle objet
3.3. Définition de l'unité de persistance
3.4. Assemblage de notre application
3.5. Assemblage et déploiement
3.6. Utilisation du client
4. Opération de persistance en façade
4.1. Introduction
4.2. Enrichissement du service
4.3. Création de la méthode findMarinById(long)
4.4. Ajout de la méthode findAllMarins()
4.5. Utilisation dans un code client
5. Types d'EJB
5.1. Introduction
5.2. Qu'est-ce qu'un EJB ?
5.3. Écriture d'un EJB session
5.4. Qu'est-ce qu'une méthode métier ?
5.5. EJB avec ou sans état
5.6. Gestion des transactions
5.7. Restrictions
6. Cycle de vie d'un EJB
6.1. Cas des EJB sans état
6.2. Cas des EJB avec état
6.3. Injection de dépendances
7. Transaction gérée par l'EJB
7.1. Introduction
7.2. Déclaration du mode transactionnel
7.3. Gestion de la transaction
7.4. Fonctionnement de la transaction
7.5. Cas des EJB avec état
8. Transaction gérée par le serveur
8.1. Introduction
8.2. Déclaration du mode transactionnel
8.3. Gestion de la transaction
8.4. Fonctionnement de la transaction
8.5. Remarques
9. Intercepteurs
9.1. Introduction
9.2. Aperçu général
9.3. Cycle de vie d'un intercepteur
9.4. Object InvocationContext
9.5. Interception d'un EJB ou d'une méthode métier
9.6. Exemple de mise en œuvre d'un intercepteur