21.3. 级联生命周期(Cascading lifecycle)

需要显式调用save()仍然很麻烦,我们可以用级联来解决这个问题。

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

这样上面的代码可以简化为:

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

同样的,保存或删除Parent对象的时候并不需要遍历其子对象。 下面的代码会删除对象p及其所有子对象对应的数据库记录。

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

然而,这段代码

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

不会从数据库删除c;它只会删除与p之间的连接(并且会导致违反NOT NULL约束,在这个例子中)。你需要显式调用delete()来删除Child

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

在我们的例子中,如果没有父对象,子对象就不应该存在,如果将子对象从collection中移除,实际上我们是想删除它。要实现这种要求,就必须使用cascade="all-delete-orphan"

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

注意:即使在collection一方的映射中指定inverse="true",级联仍然是通过遍历collection中的元素来处理的。如果你想要通过级联进行子对象的插入、删除、更新操作,就必须把它加到collection中,只调用setParent()是不够的。