個々のオブジェクトをセーブしたり、削除したり、再追加したりすることはかなり面倒です。特に、関連するオブジェクトを扱うような場合には際立ちます。よくあるのは、親子関係を扱うケースです。以下の例を考えてみましょう:
もし、親子関係の子が値型なら(例えば、住所や文字列のコレクション)、それらのライフサイクルは親に依存しており、便利な状態変化の「カスケード」を使うために、追加の作業は必要はありません。親がセーブされたとき、値型の子オブジェクトも同じようにセーブされますし、親が削除されたときは、子も削除されます。その他の操作も同じです。コレクションから1つの子を削除するような操作でもうまくいきます。すなわち、 Hibernate はこの削除操作を検出すると、値型のオブジェクトは参照を共有できないので、データベースからその子供を削除します。
ここで、親と子が値型でなくエンティティであるとして同じシナリオを考えてみましょう。(例えば、カテゴリーと品目の関係や親と子の猫の関係です。)エンティティは、それ自身がライフサイクルを持ち、参照の共有をサポートします。(そのため、コレクションからエンティティを削除することは、エンティティ自身の削除を意味しません。)また、エンティティは、デフォルトでは、関連する他のエンティティへ状態をカスケードすることはありません。 Hibernate は 到達可能性による永続化 をデフォルトでは実行しません。
Hibernate の Session の基本操作( persist(), merge(), saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate() が含まれます)に対して、それぞれに対応するカスケードスタイルがあります。それぞれのカスケードスタイルには、 create, merge, save-update, delete, lock, refresh, evict, replicate という名前がついています。もし、関連に沿ってカスケードさせたい操作があるなら、マッピングファイルにそう指定しなければなりません。例えば、以下のようにします:
<one-to-one name="person" cascade="persist"/>
カスケードスタイルは、組み合わせることができます:
<one-to-one name="person" cascade="persist,delete,lock"/>
すべての 操作を関連に沿ってカスケードするよう指定するときは、 cascade="all" を使います。デフォルトの cascade="none" は、どの操作もカスケードしないことを意味します。
特殊なカスケードスタイル delete-orphan は、一対多関連にだけ適用できます。これは、関連から削除された子供のオブジェクトに対して、 delete() 操作が適用されることを意味します。
おすすめ:
普通、 <many-to-one> や <many-to-many> 関連に対しては、カスケードを設定する意味はありません。 <one-to-one> と <one-to-many> 関連に対しては、カスケードが役に立つことがあります。
子供オブジェクトの寿命が親オブジェクトの寿命に制限を受けるならば、 cascade="all,delete-orphan" を指定し、子供オブジェクトを ライフサイクルオブジェクト にします。
それ以外の場合は、カスケードはほとんど必要ないでしょう。しかし、同じトランザクションのなかで親と子が一緒に動作することが多いと思い、いくらかのコードを書く手間を省きたいのであれば、 cascade="persist,merge,save-update" を使うことを考えましょう。
cascade="all" でマッピングした関連(単値関連やコレクション)は、 親子 スタイルの関連とマークされます。それは、親のセーブ/更新/削除が、子のセーブ/更新/削除を引き起こす関係のことです。
さらに、永続化された親が子を単に参照しているだけで、子のセーブ/更新を引き起こします。しかし、このメタファーは不完全です。親から参照されなくなった子は、自動的に削除 されません 。ただし、 cascade="delete-orphan" でマッピングされた <one-to-many> 関連を除いてです。親子関係のカスケード操作の正確な意味は以下のようになります:
親が persist() に渡されたならば、すべての子は persist() に渡されます。
merge() に渡されたならば、すべての子は merge() に渡されます。
親が save() 、 update() 、 saveOrUpdate() に渡されたならば、すべての子は saveOrUpdate() に渡されます。
transient または detached の子が、永続化された親に参照されたならば、 saveOrUpdate() に渡されます。
親が削除されたならば、すべての子は、 delete() に渡されます。
子が永続化された親から参照されなくなったときは、 特に何も起こりません 。よって、アプリケーションが必要であれば、明示的に削除する必要があります。ただし、 cascade="delete-orphan" の場合を除きます。この場合、「親のない」子は削除されます。
最後に、操作のカスケードがオブジェクトグラフに適用されるのは、 コールした時 あるいは、 flushした時 であることに注意してください。すべての操作は、その操作が実行されたときに、到達可能な関連するエンティティに対してカスケードが可能ならカスケードします。しかし、 save-upate と delete-orphan は、 Session が flush している間に、すべての到達可能な関連するエンティティに伝播します。