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
.
@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 }
@OneToMany
classique, dans laquelle l'entité maître est
Commune
. Examinons le schéma généré par JPA.
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é.
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 }
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.
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.
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 }
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.