21.3. Cascading lifecycle
The explicit call to save()
is still annoying. We will address this by using cascades.
<set name="children" inverse="true" cascade="all">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
This simplifies the code above to
Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
p.addChild(c);
session.flush();
Similarly, we don't need to iterate over the children when saving or deleting a Parent
. The following removes p
and all its children from the database.
Parent p = (Parent) session.load(Parent.class, pid);
session.delete(p);
session.flush();
However, this 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();
will not remove c
from the database; it will ony remove the link to p
(and cause a NOT NULL
constraint violation, in this case). You need to explicitly delete()
the 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();
Now, in our case, a Child
can't really exist without its parent. So if we remove a Child
from the collection, we really do want it to be deleted. For this, we must use cascade="all-delete-orphan"
.
<set name="children" inverse="true" cascade="all-delete-orphan">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
Note: even though the collection mapping specifies inverse="true"
, cascades are still processed by iterating the collection elements. So if you require that an object be saved, deleted or updated by cascade, you must add it to the collection. It is not enough to simply call setParent()
.