mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-28 23:09:13 +00:00
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@8684 1b8cb986-b30d-0410-93ca-fae66ebed9b2
1217 lines
51 KiB
XML
1217 lines
51 KiB
XML
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
<chapter id="collections">
|
|
<title>Mapping des collections</title>
|
|
|
|
<sect1 id="collections-persistent" revision="3">
|
|
<title>Collections persistantes</title>
|
|
|
|
<para>
|
|
Hibernate requiert que les champs contenant des collections persistantes soient déclarés
|
|
comme des types d'interface, par exemple :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[public class Product {
|
|
private String serialNumber;
|
|
private Set parts = new HashSet();
|
|
|
|
public Set getParts() { return parts; }
|
|
void setParts(Set parts) { this.parts = parts; }
|
|
public String getSerialNumber() { return serialNumber; }
|
|
void setSerialNumber(String sn) { serialNumber = sn; }
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
L'interface réelle devrait être <literal>java.util.Set</literal>,
|
|
<literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
|
|
<literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
|
|
<literal>java.util.SortedMap</literal> ou ... n'importe quoi d'autre ! (Où
|
|
"n'importe quoi d'autre" signifie que vous devrez écrire une implémentation de
|
|
<literal>org.hibernate.usertype.UserCollectionType</literal>.)
|
|
</para>
|
|
|
|
<para>
|
|
Notez comment nous avons initialisé les variables d'instance avec une instance de
|
|
<literal>HashSet</literal>. C'est le meilleur moyen pour initialiser les
|
|
collections d'instances nouvellement créées (non persistantes). Quand
|
|
nous fabriquons l'instance persistante - en appelant <literal>persist()</literal>,
|
|
par exemple - Hibernate remplacera réellement le <literal>HashSet</literal>
|
|
avec une instance d'une implémentation propre à Hibernate de <literal>Set</literal>.
|
|
Prenez garde aux erreurs :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Cat cat = new DomesticCat();
|
|
Cat kitten = new DomesticCat();
|
|
....
|
|
Set kittens = new HashSet();
|
|
kittens.add(kitten);
|
|
cat.setKittens(kittens);
|
|
session.persist(cat);
|
|
kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|
(HashSet) cat.getKittens(); // Erreur !]]></programlisting>
|
|
|
|
<para>
|
|
Les collections persistantes injectées par Hibernate se comportent de la même manière que
|
|
<literal>HashMap</literal>, <literal>HashSet</literal>,
|
|
<literal>TreeMap</literal>, <literal>TreeSet</literal> ou
|
|
<literal>ArrayList</literal>, selon le type de l'interface.
|
|
</para>
|
|
|
|
<para>
|
|
Les instances des collections ont le comportement habituel des types des valeurs.
|
|
Elles sont automatiquement persistées quand elles sont référencées par un objet persistant et
|
|
automatiquement effacées quand elles sont déréférencées. Si une collection est passée
|
|
d'un objet persistant à un autre, ses éléments pourraient être déplacés d'une table
|
|
à une autre. Deux entités ne peuvent pas partager une référence vers une même instance
|
|
d'une collection. Dû au modèle relationnel sous-jacent, les propriétés contenant des
|
|
collections ne supportent pas la sémantique de la valeur null ; Hibernate ne distingue pas
|
|
une référence vers une collection nulle d'une collection vide.
|
|
</para>
|
|
|
|
<para>
|
|
Vous ne devriez pas vous préoccuper trop de ça. Utilisez les collections persistantes de
|
|
la même manière que vous utilisez des collections Java ordinaires. Assurez-vous
|
|
de comprendre la sémantique des associations bidirectionnelles (traitée plus loin).
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="collections-mapping" revision="4">
|
|
<title>Mapper une collection</title>
|
|
|
|
<para>
|
|
L'élément de mapping d'Hibernate utilisé pour mapper une collection dépend du type de
|
|
l'interface. Par exemple, un élément <literal><set></literal> est utilisé
|
|
pour mapper des propriétés de type <literal>Set</literal>.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Product">
|
|
<id name="serialNumber" column="productSerialNumber"/>
|
|
<set name="parts">
|
|
<key column="productSerialNumber" not-null="true"/>
|
|
<one-to-many class="Part"/>
|
|
</set>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
À part <literal><set></literal>, il y aussi les éléments de mapping
|
|
<literal><list></literal>, <literal><map></literal>,
|
|
<literal><bag></literal>, <literal><array></literal> et
|
|
<literal><primitive-array></literal>.
|
|
L'élément <literal><map></literal> est représentatif :
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="mappingcollection1" coords="2 65"/>
|
|
<area id="mappingcollection2" coords="3 65"/>
|
|
<area id="mappingcollection3" coords="4 65"/>
|
|
<area id="mappingcollection4" coords="5 65"/>
|
|
<area id="mappingcollection5" coords="6 65"/>
|
|
<area id="mappingcollection6" coords="7 65"/>
|
|
<area id="mappingcollection7" coords="8 65"/>
|
|
<area id="mappingcollection8" coords="9 65"/>
|
|
<area id="mappingcollection9" coords="10 65"/>
|
|
<area id="mappingcollection10" coords="11 65"/>
|
|
<area id="mappingcollection11" coords="12 65"/>
|
|
<area id="mappingcollection12" coords="13 65"/>
|
|
<area id="mappingcollection13" coords="14 65"/>
|
|
<area id="mappingcollection14" coords="15 65"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<map
|
|
name="nomDePropriete"
|
|
table="nom_de_table"
|
|
schema="nom_du_schema"
|
|
lazy="true|extra|false"
|
|
inverse="true|false"
|
|
cascade="all|none|save-update|delete|all-delete-orphan"
|
|
sort="unsorted|natural|ClasseDeComparateur"
|
|
order-by="nom_de_column asc|desc"
|
|
where="condition sql where quelcconque"
|
|
fetch="join|select|subselect"
|
|
batch-size="N"
|
|
access="field|property|NomDeClasse"
|
|
optimistic-lock="true|false"
|
|
mutable="true|false"
|
|
node="nom-d-element|."
|
|
embed-xml="true|false"
|
|
>
|
|
|
|
<key .... />
|
|
<map-key .... />
|
|
<element .... />
|
|
</map>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="mappingcollection1">
|
|
<para>
|
|
<literal>name</literal> : le nom de la propriété contenant la collection
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection2">
|
|
<para>
|
|
<literal>table</literal> (optionnel - par défaut = nom de la propriété) : le
|
|
nom de la table de la collection (non utilisé pour les associations one-to-many)
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection3">
|
|
<para>
|
|
<literal>schema</literal> (optionnel) : le nom du schéma pour surcharger le
|
|
schéma déclaré dans l'élément racine
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection4">
|
|
<para>
|
|
<literal>lazy</literal> (optionnel - par défaut = <literal>true</literal>) :
|
|
peut être utilisé pour désactiver l'initialisation tardive et spécifier
|
|
que l'association est toujours rapportée, ou pour activer la
|
|
récupération extra-paresseuse (NdT : extra-lazy) où la plupart des
|
|
opérations n'initialisent pas la collection (approprié pour de très
|
|
grosses collections)
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection5">
|
|
<para>
|
|
<literal>inverse</literal> (optionnel - par défaut = <literal>false</literal>) :
|
|
définit cette collection comme l'extrêmité "inverse" de l'association
|
|
bidirectionnelle
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection6">
|
|
<para>
|
|
<literal>cascade</literal> (optionnel - par défaut = <literal>none</literal>) :
|
|
active les opérations de cascade vers les entités filles
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection7">
|
|
<para>
|
|
<literal>sort</literal> (optionnel) : spécifie une collection triée via un ordre
|
|
de tri <literal>naturel</literal>, ou via une classe comparateur donnée (implémentant Comparator)
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection8">
|
|
<para>
|
|
<literal>order-by</literal> (optionnel, seulement à partir du JDK1.4) :
|
|
spécifie une colonne de table
|
|
(ou des colonnes) qui définit l'ordre d'itération de <literal>Map</literal>, <literal>Set</literal>
|
|
ou Bag, avec en option <literal>asc</literal> ou <literal>desc</literal>
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection9">
|
|
<para>
|
|
<literal>where</literal> (optionnel) : spécifie une condition SQL arbitraire <literal>WHERE</literal>
|
|
à utiliser au chargement ou à la suppression d'une collection (utile si la collection
|
|
ne doit contenir qu'un sous ensemble des données disponibles)
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection10">
|
|
<para>
|
|
<literal>fetch</literal> (optionnel, par défaut = <literal>select</literal>) :
|
|
à choisir entre récupération par jointures externes, récupération par
|
|
selects séquentiels, et récupération par sous-selects séquentiels
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection11">
|
|
<para>
|
|
<literal>batch-size</literal> (optionnel, par défaut = <literal>1</literal>) : une taille
|
|
de batch (batch size) utilisée pour charger plusieurs instances de cette collection en
|
|
initialisation tardive
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection12">
|
|
<para>
|
|
<literal>access</literal> (optionnel - par défaut = <literal>property</literal>) : La
|
|
stratégie qu'Hibernate doit utiliser pour accéder à la valeur de la propriété
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection13">
|
|
<para>
|
|
<literal>optimistic-lock</literal> (optionnel - par défaut = <literal>true</literal>) :
|
|
spécifie que changer l'état de la collection entraîne l'incrémentation
|
|
de la version appartenant à l'entité (Pour une association un vers plusieurs,
|
|
il est souvent raisonnable de désactiver ce paramètre)
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection14">
|
|
<para>
|
|
<literal>mutable</literal> (optionnel - par défaut = <literal>true</literal>) :
|
|
une valeur à <literal>false</literal> spécifie que les éléments de la
|
|
collection ne changent jamais (une optimisation mineure dans certains cas)
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<sect2 id="collections-foreignkeys" >
|
|
<title>Les clefs étrangères d'une collection</title>
|
|
|
|
<para>
|
|
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)
|
|
<emphasis>colonne(s) de la clef de la collection</emphasis> de la table de la collection.
|
|
La colonne de la clef de la collection est mappée par l'élément <literal><key></literal>.
|
|
</para>
|
|
|
|
<para>
|
|
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
|
|
<literal>not-null="true"</literal>.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
|
|
|
|
<para>
|
|
La contraite de la clef étrangère peut utiliser <literal>ON DELETE CASCADE</literal>.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
|
|
|
|
<para>
|
|
Voir le chapitre précédent pour une définition complète de l'élément <literal><key></literal>.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-elements" >
|
|
<title>Les éléments d'une collection</title>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
Le type contenu est référencé comme le <emphasis>type de l'élément de la collection</emphasis>.
|
|
Les éléments de la collections sont mappés par <literal><element></literal> ou
|
|
<literal><composite-element></literal>, ou dans le cas des références d'entité, avec
|
|
<literal><one-to-many></literal> ou <literal><many-to-many></literal>.
|
|
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é.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-indexed">
|
|
<title>Collections indexées</title>
|
|
|
|
<para>
|
|
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 <emphasis>colonne d'index</emphasis> dans la
|
|
table de la collection - une colonne qui mappe un index de tableau, ou un index de
|
|
<literal>List</literal>, ou une clef de <literal>Map</literal>. L'index d'une
|
|
<literal>Map</literal> peut être n'importe quel type basique, mappé avec
|
|
<literal><map-key></literal>, ça peut être une référence d'entité mappée avec
|
|
<literal><map-key-many-to-many></literal>, ou ça peut être un type composé, mappé avec
|
|
<literal><composite-map-key></literal>. L'index d'un tableau ou d'une liste est toujours
|
|
de type <literal>integer</literal> et est mappé en utilisant l'élément <literal><list-index></literal>.
|
|
Les colonnes mappées contiennent des entiers séquentiels (numérotés à partir de zéro par défaut).
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="index1" coords="2 45"/>
|
|
<area id="index2" coords="3 45"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<list-index
|
|
column="nom_de_colonne"
|
|
base="0|1|..."/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="index1">
|
|
<para>
|
|
<literal>nom_de_colonne</literal> (requis) : le nom de la colonne contenant les valeurs de l'index de la collection
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="index1">
|
|
<para>
|
|
<literal>base</literal> (optionnel, par défaut = <literal>0</literal>) : la valeur
|
|
de la colonne de l'index qui correspond au premier élément de la liste ou du tableau
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="mapkey1" coords="2 45"/>
|
|
<area id="mapkey2" coords="3 45"/>
|
|
<area id="mapkey3" coords="4 45"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<map-key
|
|
column="nom_de_colonne"
|
|
formula="n'importe quelle expression SQL"
|
|
type="nom_du_type"
|
|
node="@nom-d-attribut"
|
|
length="N"/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="mapkey1">
|
|
<para>
|
|
<literal>column</literal> (optionnel) :
|
|
le nom de la colonne contenant les valeurs de l'index de la collection
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mapkey2">
|
|
<para>
|
|
<literal>formula</literal> (optionnel) :
|
|
une formule SQL utilisée pour évaluer la clef de la map
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mapkey3">
|
|
<para>
|
|
<literal>type</literal> (reguis): le type des clefs de la map
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="indexmanytomany1" coords="2 45"/>
|
|
<area id="indexmanytomany2" coords="3 45"/>
|
|
<area id="indexmanytomany3" coords="3 45"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<map-key-many-to-many
|
|
column="nom_de_colonne"
|
|
formula="n'importe quelle expression SQL"
|
|
class="NomDeClasse"
|
|
/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="indexmanytomany1">
|
|
<para>
|
|
<literal>column</literal> (optionnel) :
|
|
le nom de la colonne de la clef étrangère pour les valeurs de l'index de la collection
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="indexmanytomany2">
|
|
<para>
|
|
<literal>formula</literal> (optionnel) :
|
|
une formulre SQL utilisée pour évaluer la clef étrangère de la clef de la map
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="indexmanytomany3">
|
|
<para>
|
|
<literal>class</literal> (requis): la classe de l'entité utilisée comme clef de la map
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
<para>
|
|
Si votre table n'a pas de colonne d'index, et que vous souhaitez tout de même utiliser
|
|
<literal>List</literal> comme type de propriété, vous devriez mapper la propriété comme un
|
|
<emphasis><bag></emphasis> 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é.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<sect2 id="collections-ofvalues" revision="2">
|
|
<title>Collections de valeurs et associations plusieurs-vers-plusieurs</title>
|
|
|
|
<para>
|
|
N'importe quelle collection de valeurs ou association plusieurs-vers-plusieurs requiert une
|
|
<emphasis>table de collection</emphasis> avec une(des) colonne(s) de clef étrangère, une(des)
|
|
<emphasis>colonne(s) d'élément de la collection</emphasis> ou des colonnes et possiblement
|
|
une(des) colonne(s) d'index.
|
|
</para>
|
|
|
|
<para>
|
|
Pour une collection de valeurs, nous utilisons la balise <literal><element></literal>.
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="element1b" coords="2 50"/>
|
|
<area id="element2b" coords="3 50"/>
|
|
<area id="element3b" coords="4 50"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<element
|
|
column="nom_de_colonne"
|
|
formula="n'importe quelle expression SQL"
|
|
type="nomDeType"
|
|
length="L"
|
|
precision="P"
|
|
scale="S"
|
|
not-null="true|false"
|
|
unique="true|false"
|
|
node="nom-d-element"
|
|
/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="element1b">
|
|
<para>
|
|
<literal>column</literal> (optionnel) : le nom de la colonne contenant les valeurs de l'élément de la collection
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="element2b">
|
|
<para>
|
|
<literal>formula</literal> (optionnel) : une formule SQL utilisée pour évaluer l'élément
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="element3b">
|
|
<para>
|
|
<literal>type</literal> (requis) : le type de l'élément de la collection
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<para>
|
|
Une <emphasis>association plusieurs-vers-plusieurs</emphasis> est spécifiée en
|
|
utilisant l'élément <literal><many-to-many></literal>.
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="manytomany1" coords="2 60"/>
|
|
<area id="manytomany2" coords="3 60"/>
|
|
<area id="manytomany3" coords="4 60"/>
|
|
<area id="manytomany4" coords="5 60"/>
|
|
<area id="manytomany5" coords="6 60"/>
|
|
<area id="manytomany6" coords="7 60"/>
|
|
<area id="manytomany7" coords="8 60"/>
|
|
<area id="manytomany8" coords="9 60"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<many-to-many
|
|
column="nom_de_colonne"
|
|
formula="n'importe quelle expression SQL"
|
|
class="NomDeClasse"
|
|
fetch="select|join"
|
|
unique="true|false"
|
|
not-found="ignore|exception"
|
|
entity-name="NomDEntite"
|
|
property-ref="nomDeProprieteDeLaClasseAssociee"
|
|
node="nom-d-element"
|
|
embed-xml="true|false"
|
|
/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="manytomany1">
|
|
<para>
|
|
<literal>column</literal> (optionnel) : le nom de la colonne de la clef étrangère de l'élément
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany2">
|
|
<para>
|
|
<literal>formula</literal> (optionnel) :
|
|
une formule SQL utilisée pour évaluer la valeur de la clef étrangère de l'élément
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany3">
|
|
<para>
|
|
<literal>class</literal> (requis) : le nom de la classe associée
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany4">
|
|
<para>
|
|
<literal>fetch</literal> (optionnel - par défaut <literal>join</literal>) :
|
|
active les récupérations par jointures externes ou par selects séquentiels pour cette association.
|
|
C'est un cas spécial ; pour une récupération complète sans attente (dans un seul <literal>SELECT</literal>) d'une
|
|
entité et de ses relations plusieurs-vers-plusieurs vers d'autres entités,
|
|
vous devriez activer la récupération <literal>join</literal> non seulement sur
|
|
la collection elle-même, mais aussi avec cet attribut sur l'élément imbriqué
|
|
<literal><many-to-many></literal>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany5">
|
|
<para>
|
|
<literal>unique</literal> (optionnel) : activer la génération DDL d'une
|
|
contrainte d'unicité pour la colonne de la clef étrangère. Ça rend la pluralité
|
|
de l'association effectivement un-vers-plusieurs.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany6">
|
|
<para>
|
|
<literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
|
|
spécifie comment les clefs étrangères qui référencent la lignes
|
|
manquantes seront gérées : <literal>ignore</literal> traitera
|
|
une ligne manquante comme une association nulle.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany7">
|
|
<para>
|
|
<literal>entity-name</literal> (optionnel) : le nom de l'entité de la classe associée, comme une alternative à <literal>class</literal>
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany8">
|
|
<para>
|
|
<literal>property-ref</literal> (optionnel) : le nom d'une propriété de
|
|
la classe associée qui est jointe à cette clef étrangère. Si non spécifiée,
|
|
la clef primaire de la classe associée est utilisée.
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<para>
|
|
Quelques exemples, d'abord, un ensemble de chaînes de caractères :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<set name="names" table="person_names">
|
|
<key column="person_id"/>
|
|
<element column="person_name" type="string"/>
|
|
</set>]]></programlisting>
|
|
|
|
<para>
|
|
Un bag contenant des entiers (avec un ordre d'itération déterminé par l'attribut <literal>order-by</literal>) :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<bag name="sizes"
|
|
table="item_sizes"
|
|
order-by="size asc">
|
|
<key column="item_id"/>
|
|
<element column="size" type="integer"/>
|
|
</bag>]]></programlisting>
|
|
|
|
<para>
|
|
Un tableau d'entités - dans ce cas, une association plusieurs-vers-plusieurs :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<array name="addresses"
|
|
table="PersonAddress"
|
|
cascade="persist">
|
|
<key column="personId"/>
|
|
<list-index column="sortOrder"/>
|
|
<many-to-many column="addressId" class="Address"/>
|
|
</array>]]></programlisting>
|
|
|
|
<para>
|
|
Une map de chaînes de caractères vers des dates :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
|
|
<para>
|
|
Une liste de composants (discute dans le prochain chapitre) :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-onetomany">
|
|
<title>Association un-vers-plusieurs</title>
|
|
|
|
<para>
|
|
Une <emphasis>association un vers plusieurs</emphasis> 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 :
|
|
</para>
|
|
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para>
|
|
Une instance de la classe de l'entité contenue ne peut pas appartenir à plus d'une
|
|
instance de la collection
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Une instance de la classe de l'entité contenue ne peut pas apparaître plus plus d'une valeur d'index de la collection
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Une association de <literal>Product</literal> vers <literal>Part</literal> requiert l'existence d'une
|
|
clef étrangère et possiblement une colonne d'index pour la table <literal>Part</literal>. Une balise
|
|
<literal><one-to-many></literal> indique que c'est une association un vers plusieurs.
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="onetomany1" coords="2 60"/>
|
|
<area id="onetomany2" coords="3 60"/>
|
|
<area id="onetomany3" coords="4 60"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<one-to-many
|
|
class="NomDeClasse"
|
|
not-found="ignore|exception"
|
|
entity-name="NomDEntite"
|
|
node="nom-d-element"
|
|
embed-xml="true|false"
|
|
/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="onetomany1">
|
|
<para>
|
|
<literal>class</literal> (requis) : le nom de la classe associée
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="onetomany2">
|
|
<para>
|
|
<literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
|
|
spécifie comment les identifiants cachés qui référencent des lignes manquantes seront gérés :
|
|
<literal>ignore</literal> traitera une ligne manquante comme une association nulle
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="onetomany3">
|
|
<para>
|
|
<literal>entity-name</literal> (optionnel) : le nom de l'entité de la
|
|
classe associée, comme une alternative à <literal>class</literal>.
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<para>
|
|
Notez que l'élément <literal><one-to-many></literal> 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.
|
|
</para>
|
|
|
|
<para>
|
|
<emphasis>Note très importante :</emphasis> si la colonne de la clef d'une association
|
|
<literal><one-to-many></literal> est déclarée <literal>NOT NULL</literal>, vous devez déclarer le
|
|
mapping de <literal><key></literal> avec <literal>not-null="true"</literal> ou
|
|
<emphasis>utiliser une association bidirectionnelle</emphasis> avec le mapping de la
|
|
collection marqué <literal>inverse="true"</literal>. Voir la discussion sur les associations bidirectionnelles plus tard dans ce chapitre.
|
|
</para>
|
|
|
|
<para>
|
|
Cet exemple montre une map d'entités <literal>Part</literal> par nom (où
|
|
<literal>partName</literal> est une propriété persistante de <literal>Part</literal>).
|
|
Notez l'utilisation d'un index basé sur une formule.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<map name="parts"
|
|
cascade="all">
|
|
<key column="productId" not-null="true"/>
|
|
<map-key formula="partName"/>
|
|
<one-to-many class="Part"/>
|
|
</map>]]></programlisting>
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="collections-advancedmappings">
|
|
<title>Mappings de collection avancés</title>
|
|
|
|
<sect2 id="collections-sorted" revision="2">
|
|
<title>Collections triées</title>
|
|
|
|
<para>
|
|
Hibernate supporte des collections implémentant <literal>java.util.SortedMap</literal> et
|
|
<literal>java.util.SortedSet</literal>. Vous devez spécifier un comparateur dans le fichier de mapping :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<set name="aliases"
|
|
table="person_aliases"
|
|
sort="natural">
|
|
<key column="person"/>
|
|
<element column="name" type="string"/>
|
|
</set>
|
|
|
|
<map name="holidays" sort="my.custom.HolidayComparator">
|
|
<key column="year_id"/>
|
|
<map-key column="hol_name" type="string"/>
|
|
<element column="hol_date" type="date"/>
|
|
</map>]]></programlisting>
|
|
|
|
<para>
|
|
Les valeurs permises pour l'attribut <literal>sort</literal> sont <literal>unsorted</literal>,
|
|
<literal>natural</literal> et le nom d'une classe implémentant
|
|
<literal>java.util.Comparator</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
Les collections triées se comportent réellement comme <literal>java.util.TreeSet</literal> ou
|
|
<literal>java.util.TreeMap</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
Si vous voulez que la base de données elle-même ordonne les éléments de la collection, utilisez l'attribut
|
|
<literal>order-by</literal> des mappings <literal>set</literal>, <literal>bag</literal>
|
|
ou <literal>map</literal>. Cette solution est seulement disponible à partir du JDK 1.4 (c'est
|
|
implémenté en utilisant <literal>LinkedHashSet</literal> ou
|
|
<literal>LinkedHashMap</literal>). Ceci exécute le tri dans la requête SQL, pas en mémoire.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
|
|
<key column="person"/>
|
|
<element column="name" type="string"/>
|
|
</set>
|
|
|
|
<map name="holidays" order-by="hol_date, hol_name">
|
|
<key column="year_id"/>
|
|
<map-key column="hol_name" type="string"/>
|
|
<element column="hol_date type="date"/>
|
|
</map>]]></programlisting>
|
|
|
|
<para>
|
|
Notez que la valeur de l'attribut <literal>order-by</literal> est un ordre SQL, pas un ordre HQL !
|
|
</para>
|
|
|
|
<para>
|
|
Les associations peuvent même être triées sur des critères arbitraires à l'exécution en utilisant un <literal>filter()</literal> de collection.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-bidirectional" revision="1">
|
|
<title>Associations bidirectionnelles</title>
|
|
|
|
<para>
|
|
Une <emphasis>association bidirectionnelle</emphasis> permet une navigation à
|
|
partir de la "fin" de l'association. Deux sortes d'associations bidirectionnelles sont supportées :
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term>un-vers-plusieurs (NdT : one-to-many)</term>
|
|
<listitem>
|
|
<para>
|
|
ensemble ou sac à une extrémité, une seule valeur à l'autre
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>plusieurs-vers-plusieurs (NdT : many-to-many)</term>
|
|
<listitem>
|
|
<para>
|
|
ensemble ou sac aux deux extrémités
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</para>
|
|
|
|
<para>
|
|
Vous pouvez spécifier une association plusieurs-vers-plusieurs bidirectionnelle simplement
|
|
en mappant deux associations plusieurs-vers-plusieurs vers la même table de base de données et en déclarant une extrémité comme <emphasis>inverse</emphasis> (celle de votre choix, mais ça ne peut pas être une collection indexée).
|
|
</para>
|
|
|
|
<para>
|
|
Voici un exemple d'association bidirectionnelle plusieurs-vers-plusieurs ; chaque catégorie peut
|
|
avoir plusieurs objets et chaque objet peut être dans plusieurs catégories :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Category">
|
|
<id name="id" column="CATEGORY_ID"/>
|
|
...
|
|
<bag name="items" table="CATEGORY_ITEM">
|
|
<key column="CATEGORY_ID"/>
|
|
<many-to-many class="Item" column="ITEM_ID"/>
|
|
</bag>
|
|
</class>
|
|
|
|
<class name="Item">
|
|
<id name="id" column="CATEGORY_ID"/>
|
|
...
|
|
|
|
<!-- inverse end -->
|
|
<bag name="categories" table="CATEGORY_ITEM" inverse="true">
|
|
<key column="ITEM_ID"/>
|
|
<many-to-many class="Category" column="CATEGORY_ID"/>
|
|
</bag>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
Les changements faits uniquement sur l'extréminté inverse de l'association <emphasis>ne sont pas</emphasis>
|
|
persistés. Ceci signifie qu'Hibernate a deux représentations en mémoire pour chaque
|
|
association bidirectionnelles, un lien de A vers B et un autre de B vers A. C'est
|
|
plus facile à comprendre si vous pensez au modèle objet de Java et comment nous
|
|
créons une relation plusieurs-vers-plusieurs en Java :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[
|
|
category.getItems().add(item); // La catégorie est maintenant "au courant" de la relation
|
|
item.getCategories().add(category); // L'objet est maintenant "au courant" de la relation
|
|
|
|
session.persist(item); // La relation ne sera pas sauvegardée !
|
|
session.persist(category); // La relation sera sauvegardée]]></programlisting>
|
|
|
|
<para>
|
|
La partie non-inverse est utilisée pour sauvegarder la représentation en mémoire dans la base de données.
|
|
</para>
|
|
|
|
<para>
|
|
Vous pouvez définir une association un-vers-plusieurs bidirectionnelle en mappant une
|
|
association un-vers-plusieurs vers la(es) même(s) colonne(s) de table qu'une association
|
|
plusieurs-vers-un et en déclarant l'extrémité pluri-valuée <literal>inverse="true"</literal>.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Parent">
|
|
<id name="id" column="parent_id"/>
|
|
....
|
|
<set name="children" inverse="true">
|
|
<key column="parent_id"/>
|
|
<one-to-many class="Child"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id" column="child_id"/>
|
|
....
|
|
<many-to-one name="parent"
|
|
class="Parent"
|
|
column="parent_id"
|
|
not-null="true"/>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
Mapper une extrémité d'une association avec <literal>inverse="true"</literal> n'affecte
|
|
pas l'opération de cascades, ce sont des concepts orthogonaux !
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-indexedbidirectional">
|
|
<title>Associations bidirectionnelles avec des collections indexées</title>
|
|
<para>
|
|
Une association bidirectionnelle où une extrémité est représentée comme une <literal><list></literal>
|
|
ou une <literal><map></literal> requiert une considération spéciale. Si il y a une
|
|
propriété de la classe enfant qui mappe la colonne de l'index, pas de problème, nous pouvons
|
|
continuer à utiliser <literal>inverse="true"</literal> sur le mapping de la collection :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Parent">
|
|
<id name="id" column="parent_id"/>
|
|
....
|
|
<map name="children" inverse="true">
|
|
<key column="parent_id"/>
|
|
<map-key column="name"
|
|
type="string"/>
|
|
<one-to-many class="Child"/>
|
|
</map>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id" column="child_id"/>
|
|
....
|
|
<property name="name"
|
|
not-null="true"/>
|
|
<many-to-one name="parent"
|
|
class="Parent"
|
|
column="parent_id"
|
|
not-null="true"/>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
Mais, si il n'y a pas de telle prorpriété sur la classe enfant, nous ne pouvons pas penser
|
|
à l'association comme vraiment bidirectionnelle (il y a des informations disponibles à une
|
|
extrémité de l'association qui ne sont pas disponibles à l'autre extrémité). Dans ce cas,
|
|
nous ne pouvons pas mapper la collection <literal>inverse="true"</literal>. À la place, nous
|
|
pourrions utiliser le mapping suivant :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Parent">
|
|
<id name="id" column="parent_id"/>
|
|
....
|
|
<map name="children">
|
|
<key column="parent_id"
|
|
not-null="true"/>
|
|
<map-key column="name"
|
|
type="string"/>
|
|
<one-to-many class="Child"/>
|
|
</map>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id" column="child_id"/>
|
|
....
|
|
<many-to-one name="parent"
|
|
class="Parent"
|
|
column="parent_id"
|
|
insert="false"
|
|
update="false"
|
|
not-null="true"/>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
Notez que dans ce mapping, l'extrémité de l'association contenant la collection est responsable
|
|
des mises à jour de la clef étrangère. À faire : cela entraîne-t-il réellement des expressions
|
|
updates inutiles ?
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-ternary">
|
|
<title>Associations ternaires</title>
|
|
|
|
<para>
|
|
Il y a trois approches possibles pour mapper une association ternaire. L'une est d'utiliser
|
|
une <literal>Map</literal> avec une association en tant qu'index :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<map name="contracts">
|
|
<key column="employer_id" not-null="true"/>
|
|
<map-key-many-to-many column="employee_id" class="Employee"/>
|
|
<one-to-many class="Contract"/>
|
|
</map>]]></programlisting>
|
|
|
|
<programlisting><![CDATA[<map name="connections">
|
|
<key column="incoming_node_id"/>
|
|
<map-key-many-to-many column="outgoing_node_id" class="Node"/>
|
|
<many-to-many column="connection_id" class="Connection"/>
|
|
</map>]]></programlisting>
|
|
|
|
<para>
|
|
Une seconde approche est simplement de remodeler l'association comme une classe d'entité. C'est
|
|
l'approche la plus commune.
|
|
</para>
|
|
|
|
<para>
|
|
Une alternative finale est d'utiliser des éléments composites, dont nous discuterons plus tard.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-idbag" revision="1">
|
|
<title>Utiliser un <literal><idbag></literal></title>
|
|
|
|
<para>
|
|
Si vous embrassez pleinement notre vue que les clefs composées sont une mauvaise
|
|
chose et que des entités devraient avoir des identifiants artificiels (des clefs
|
|
subrogées), alors vous pourriez trouver un peu curieux que les associations
|
|
plusieurs-vers-plusieurs et les collections de valeurs que nous avons montré jusqu'ici
|
|
mappent toutes des tables avec des clefs composées ! Maintenant, ce point est assez
|
|
discutable ; une table d'association pure ne semble pas beaucoup bénéficier d'une clef
|
|
subrogée (bien qu'une collection de valeur composées le <emphasis>pourrait</emphasis>).
|
|
Néanmoins, Hibernate fournit une foncionnalité qui vous permet de mapper
|
|
des associations plusieurs-vers-plusieurs et des collections de valeurs vers une
|
|
table avec une clef subrogée.
|
|
</para>
|
|
|
|
<para>
|
|
L'élément <literal><idbag></literal> vous laisse mapper une <literal>List</literal>
|
|
(ou une <literal>Collection</literal>) avec une sémantique de sac.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
|
|
<collection-id column="ID" type="long">
|
|
<generator class="sequence"/>
|
|
</collection-id>
|
|
<key column="PERSON1"/>
|
|
<many-to-many column="PERSON2" class="Person" fetch="join"/>
|
|
</idbag>]]></programlisting>
|
|
|
|
<para>
|
|
Comme vous pouvez voir, un <literal><idbag></literal> a un généréteur d'id
|
|
artificiel, comme une classe d'entité ! Une clef subrogée différente est assignée
|
|
à chaque ligne de la collection. Cependant, Hibernate ne fournit pas de mécanisme pour
|
|
découvrir la valeur d'une clef subrogée d'une ligne particulière.
|
|
</para>
|
|
|
|
<para>
|
|
Notez que les performances de la mise à jour d'un <literal><idbag></literal>
|
|
sont <emphasis>bien</emphasis> meilleures qu'un <literal><bag></literal> ordinaire !
|
|
Hibernate peut localiser des lignes individuelles efficacement et les mettre à jour ou
|
|
les effacer individuellement, comme une liste, une map ou un ensemble.
|
|
</para>
|
|
|
|
<para>
|
|
Dans l'implémentation actuelle, la stratégie de la génération de l'identifiant <literal>native</literal>
|
|
n'est pas supportée pour les identifiants de collection <literal><idbag></literal>.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<!--undocumenting this stuff -->
|
|
|
|
<!--sect1 id="collections-heterogeneous">
|
|
<title>Heterogeneous Associations</title>
|
|
|
|
<para>
|
|
The <literal><many-to-any></literal> and <literal><index-many-to-any></literal>
|
|
elements provide for true heterogeneous associations. These mapping elements work in the
|
|
same way as the <literal><any></literal> element - and should also be used
|
|
rarely, if ever.
|
|
</para>
|
|
|
|
</sect1-->
|
|
|
|
<sect1 id="collections-example" revision="1">
|
|
<title>Exemples de collections</title>
|
|
|
|
<para>
|
|
Les sections précédentes sont assez confuses. Donc prenons un exemple. Cette classe :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[package eg;
|
|
import java.util.Set;
|
|
|
|
public class Parent {
|
|
private long id;
|
|
private Set children;
|
|
|
|
public long getId() { return id; }
|
|
private void setId(long id) { this.id=id; }
|
|
|
|
private Set getChildren() { return children; }
|
|
private void setChildren(Set children) { this.children=children; }
|
|
|
|
....
|
|
....
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
a une collection d'instances de <literal>Child</literal>. Si chaque enfant
|
|
a au plus un parent, le mapping le plus naturel est une association
|
|
un-vers-plusieurs :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
|
|
<class name="Parent">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<set name="children">
|
|
<key column="parent_id"/>
|
|
<one-to-many class="Child"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<property name="name"/>
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
Ceci mappe les définitions de tables suivantes :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[create table parent ( id bigint not null primary key )
|
|
create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
|
|
alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
|
|
|
|
<para>
|
|
Si le parent est <emphasis>requis</emphasis>, utilisez une association un-vers-plusieurs unidirectionnelle :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
|
|
<class name="Parent">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<set name="children" inverse="true">
|
|
<key column="parent_id"/>
|
|
<one-to-many class="Child"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<property name="name"/>
|
|
<many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
Notez la contrainte <literal>NOT NULL</literal> :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[create table parent ( id bigint not null primary key )
|
|
create table child ( id bigint not null
|
|
primary key,
|
|
name varchar(255),
|
|
parent_id bigint not null )
|
|
alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
|
|
|
|
<para>
|
|
Alternativement, si vous insistez absolument pour que cette association soit unidirectionnelle,
|
|
vous pouvez déclarer la contrainte <literal>NOT NULL</literal> sur le mapping <literal><key></literal> :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
|
|
<class name="Parent">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<set name="children">
|
|
<key column="parent_id" not-null="true"/>
|
|
<one-to-many class="Child"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<property name="name"/>
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
D'un autre côté, si un enfant pouvait avoir plusieurs parent, une association
|
|
plusieurs-vers-plusieurs est plus appropriée :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
|
|
<class name="Parent">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<set name="children" table="childset">
|
|
<key column="parent_id"/>
|
|
<many-to-many class="Child" column="child_id"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<property name="name"/>
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
Définitions des tables :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[create table parent ( id bigint not null primary key )
|
|
create table child ( id bigint not null primary key, name varchar(255) )
|
|
create table childset ( parent_id bigint not null,
|
|
child_id bigint not null,
|
|
primary key ( parent_id, child_id ) )
|
|
alter table childset add constraint childsetfk0 (parent_id) references parent
|
|
alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
|
|
|
|
<para>
|
|
Pour plus d'exemples et une revue complète du mapping de la relation parent/enfant, voir
|
|
see <xref linkend="example-parentchild"/>.
|
|
</para>
|
|
|
|
<para>
|
|
Des mappings d'association plus exotiques sont possibles, nous cataloguerons toutes les possibilités
|
|
dans le prochain chapitre.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|