Il y a pas mal de variétés de mappings qui peuvent être générés pour les collections, couvrant beaucoup des modèles relationnels communs. Nous vous suggérons d'expérimenter avec l'outil de génération de schéma pour avoir une idée de comment traduire les différentes déclarations de mapping vers des table de la base de données.
L'élément de mapping d'Hibernate utilisé pour mapper une collection dépend du type de l'interface. Par exemple, un élément
<set>
est utilisé pour mapper des propriétés de type Set
.
<class name="Product"> <id name="serialNumber" column="productSerialNumber"/> <set name="parts"> <key column="productSerialNumber" not-null="true"/> <one-to-many class="Part"/> </set> </class>
À part <set>
, il y aussi les éléments de mapping <list>
, <map>
, <bag>
, <array>
et <primitive-array>
. L'élément <map>
est représentatif :
<map name="propertyName" (1) table="table_name" (2) schema="schema_name" (3) lazy="true|extra|false" (4) inverse="true|false" (5) cascade="all|none|save-update|delete|all-delete-orphan|delet(6)e-orphan" sort="unsorted|natural|comparatorClass" (7) order-by="column_name asc|desc" (8) where="arbitrary sql where condition" (9) fetch="join|select|subselect" (10) batch-size="N" (11) access="field|property|ClassName" (12) optimistic-lock="true|false" (13) mutable="true|false" (14) node="element-name|." embed-xml="true|false" > <key .... /> <map-key .... /> <element .... /> </map>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Les instances d'une collection sont distinguées dans la base par la clef étrangère de l'entité qui possède la collection.
Cette clef étrangère est référencée comme la(es) colonne(s) de la clef de la collection de la table de la collection. La colonne de la clef de la collection est mappée par l'élément <key>
.
Il peut y avoir une contrainte de nullité sur la colonne de la clef étrangère. Pour les associations unidirectionnelles un
vers plusieurs, la colonne de la clef étrangère peut être nulle par défaut, donc vous pourriez avoir besoin de spécifier not-null="true"
.
<key column="productSerialNumber" not-null="true"/>
La contraite de la clef étrangère peut utiliser ON DELETE CASCADE
.
<key column="productSerialNumber" on-delete="cascade"/>
Voir le chapitre précédent pour une définition complète de l'élément <key>
.
Les collections peuvent contenir la plupart des autres types Hibernate, dont tous les types basiques, les types utilisateur, les composants, et bien sûr, les références vers d'autres entités. C'est une distinction importante : un objet dans une collection pourrait être géré avec une sémantique de "valeur" (sa durée de vie dépend complètement du propriétaire de la collection) ou il pourrait avoir une référence vers une autre entité, avec sa propre durée de vie. Dans le dernier cas, seul le "lien" entre les 2 objets est considéré être l'état retenu par la collection.
Le type contenu est référencé comme le type de l'élément de la collection. Les éléments de la collections sont mappés par <element>
ou <composite-element>
, ou dans le cas des références d'entité, avec <one-to-many>
ou <many-to-many>
. Les deux premiers mappent des éléments avec un sémantique de valeur, les deux suivants sont utilisés pour mapper des associations
d'entité.
Tous les mappings de collection, exceptés ceux avec les sémantiques d'ensemble (NdT : set) et de sac (NdT : bag), ont besoin
d'une colonne d'index dans la table de la collection - une colonne qui mappe un index de tableau, ou un index de List
, ou une clef de Map
. L'index d'une Map
peut être n'importe quel type basique, mappé avec <map-key>
, ça peut être une référence d'entité mappée avec <map-key-many-to-many>
, ou ça peut être un type composé, mappé avec <composite-map-key>
. L'index d'un tableau ou d'une liste est toujours de type integer
et est mappé en utilisant l'élément <list-index>
. Les colonnes mappées contiennent des entiers séquentiels (numérotés à partir de zéro par défaut).
<list-index
column="column_name" (1)
base="0|1|..."/>
|
|
|
|
<map-key column="column_name" (1) formula="any SQL expression" (2) type="type_name" (3) node="@attribute-name" length="N"/>
|
|
|
|
|
|
<map-key-many-to-many column="column_name" (1) formula="any SQL expression" (2)(3) class="ClassName" />
|
|
|
|
|
|
Si votre table n'a pas de colonne d'index, et que vous souhaitez tout de même utiliser List
comme type de propriété, vous devriez mapper la propriété comme un <bag> Hibernate. Un sac (NdT : bag) ne garde pas son ordre quand il est récupéré de la base de données, mais il peut être optionnellement
trié ou ordonné.
N'importe quelle collection de valeurs ou association plusieurs-vers-plusieurs requiert une table de collection avec une(des) colonne(s) de clef étrangère, une(des) colonne(s) d'élément de la collection ou des colonnes et possiblement une(des) colonne(s) d'index.
Pour une collection de valeurs, nous utilisons la balise <element>
.
<element column="column_name" (1) formula="any SQL expression" (2) type="typename" (3) length="L" precision="P" scale="S" not-null="true|false" unique="true|false" node="element-name" />
|
|
|
|
|
|
A many-to-many association is specified using the <many-to-many>
element.
<many-to-many column="column_name" (1) formula="any SQL expression" (2) class="ClassName" (3) fetch="select|join" (4) unique="true|false" (5) not-found="ignore|exception" (6) entity-name="EntityName" (7) property-ref="propertyNameFromAssociatedClass" (8) node="element-name" embed-xml="true|false" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Quelques exemples, d'abord, un ensemble de chaînes de caractères :
<set name="names" table="person_names"> <key column="person_id"/> <element column="person_name" type="string"/> </set>
Un bag contenant des entiers (avec un ordre d'itération déterminé par l'attribut order-by
) :
<bag name="sizes" table="item_sizes" order-by="size asc"> <key column="item_id"/> <element column="size" type="integer"/> </bag>
Un tableau d'entités - dans ce cas, une association plusieurs-vers-plusieurs :
<array name="addresses" table="PersonAddress" cascade="persist"> <key column="personId"/> <list-index column="sortOrder"/> <many-to-many column="addressId" class="Address"/> </array>
Une map de chaînes de caractères vers des dates :
<map name="holidays" table="holidays" schema="dbo" order-by="hol_name asc"> <key column="id"/> <map-key column="hol_name" type="string"/> <element column="hol_date" type="date"/> </map>
Une liste de composants (discute dans le prochain chapitre) :
<list name="carComponents" table="CarComponents"> <key column="carId"/> <list-index column="sortOrder"/> <composite-element class="CarComponent"> <property name="price"/> <property name="type"/> <property name="serialNumber" column="serialNum"/> </composite-element> </list>
Une association un vers plusieurs lie les tables de deux classes par une clef étrangère, sans l'intervention d'une table de collection. Ce mapping perd certaines sémantiques des collections Java normales :
Une instance de la classe de l'entité contenue ne peut pas appartenir à plus d'une instance de la collection
Une instance de la classe de l'entité contenue ne peut pas apparaître plus plus d'une valeur d'index de la collection
Une association de Product
vers Part
requiert l'existence d'une clef étrangère et possiblement une colonne d'index pour la table Part
. Une balise <one-to-many>
indique que c'est une association un vers plusieurs.
<one-to-many class="ClassName" (1) not-found="ignore|exception" (2) entity-name="EntityName" (3) node="element-name" embed-xml="true|false" />
|
|
|
|
|
|
Notez que l'élément <one-to-many>
n'a pas besoin de déclarer de colonnes. Il n'est pas non plus nécessaire de spécifier le nom de la table nulle part.
Note très importante : si la colonne de la clef d'une association <one-to-many>
est déclarée NOT NULL
, vous devez déclarer le mapping de <key>
avec not-null="true"
ou utiliser une association bidirectionnelle avec le mapping de la collection marqué inverse="true"
. Voir la discussion sur les associations bidirectionnelles plus tard dans ce chapitre.
Cet exemple montre une map d'entités Part
par nom (où partName
est une propriété persistante de Part
). Notez l'utilisation d'un index basé sur une formule.
<map name="parts" cascade="all"> <key column="productId" not-null="true"/> <map-key formula="partName"/> <one-to-many class="Part"/> </map>