21.3. Cycle de vie en cascade

L'appel explicite de save() est un peu fastidieux. Nous pouvons simplifier cela en utilisant les cascades.

<set name="children" inverse="true" cascade="all">
    <key column="parent_id"/>
    <one-to-many class="Child"/>
</set>

Simplifie le code précédent en

Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
p.addChild(c);
session.flush();

De la même manière, nous n'avons pas à itérer sur les fils lorsque nous sauvons ou effacons un Parent. Le code suivant efface p et tous ses fils de la base de données.

Parent p = (Parent) session.load(Parent.class, pid);
session.delete(p);
session.flush();

Par contre, ce code

Parent p = (Parent) session.load(Parent.class, pid);
Child c = (Child) p.getChildren().iterator().next();
p.getChildren().remove(c);
c.setParent(null);
session.flush();

n'effacera pas c de la base de données, il enlèvera seulement le lien vers p (et causera une violation de contrainte NOT NULL, dans ce cas). Vous devez explicitement utiliser delete() sur Child.

Parent p = (Parent) session.load(Parent.class, pid);
Child c = (Child) p.getChildren().iterator().next();
p.getChildren().remove(c);
session.delete(c);
session.flush();

Dans notre cas, un Child ne peut pas vraiment exister sans son père. Si nous effacons un Child de la collection, nous voulons vraiment qu'il soit effacé. Pour cela, nous devons utiliser cascade="all-delete-orphan".

<set name="children" inverse="true" cascade="all-delete-orphan">
    <key column="parent_id"/>
    <one-to-many class="Child"/>
</set>

A noter : même si le mapping de la collection spécifie inverse="true", les cascades sont toujours assurées par l'itération sur les éléments de la collection. Donc, si vous avez besoin qu'un objet soit enregistré, effacé ou mis à jour par cascade, vous devez l'ajouter dans la colleciton. Il ne suffit pas d'appeler explicitement setParent().