Supposons que nous ayons une simple association <one-to-many>
de Parent
vers Child
.
<set name="children"> <key column="parent_id"/> <one-to-many class="Child"/> </set>
Si nous executions le code suivant
Parent p = .....; Child c = new Child(); p.getChildren().add(c); session.save(c); session.flush();
Hibernate exécuterait deux ordres SQL:
un INSERT
pour créer l'enregistrement pour c
un UPDATE
pour créer le lien de p
vers c
Ceci est non seuleument inefficace, mais viole aussi toute contrainte NOT NULL
sur la colonne parent_id
. Nous pouvons réparer la contrainte de nullité en spécifiant not-null="true"
dans le mapping de la collection :
<set name="children"> <key column="parent_id" not-null="true"/> <one-to-many class="Child"/> </set>
Cependant ce n'est pas la solution recommandée.
La cause sous jacente à ce comportement est que le lien (la clé étrangère parent_id
) de p
vers c
n'est pas considérée comme faisant partie de l'état de l'objet Child
et n'est donc pas créé par l'INSERT
. La solution est donc que ce lien fasse partie du mapping de Child
.
<many-to-one name="parent" column="parent_id" not-null="true"/>
(Nous avons aussi besoin d'ajouter la propriété parent
dans la classe Child
).
Maintenant que l'état du lien est géré par l'entité Child
, nous spécifions à la collection de ne pas mettre à jour le lien. Nous utilisons l'attribut inverse
.
<set name="children" inverse="true"> <key column="parent_id"/> <one-to-many class="Child"/> </set>
Le code suivant serait utilisé pour ajouter un nouveau Child
Parent p = (Parent) session.load(Parent.class, pid); Child c = new Child(); c.setParent(p); p.getChildren().add(c); session.save(c); session.flush();
Maintenant, seul un INSERT
SQL est nécessaire !
Pour alléger encore un peu les choses, nous devrions créer une méthode addChild()
dans Parent
.
public void addChild(Child c) { c.setParent(this); children.add(c); }
Le code d'ajout d'un Child
serait alors
Parent p = (Parent) session.load(Parent.class, pid); Child c = new Child(); p.addChild(c); session.save(c); session.flush();