永続クラス(JavaBeans)にlifecycleインターフェースを実装すると、永続オブジェクトのload、save、update、delete時に決まった処理を動かすことができます。
データベースで言うとトリガーのようなものでしょうか。
lifecycleインターフェースの実装
まず、永続クラスにnet.sf.hibernate.Lifecycleインターフェースをインプリメントします。永続クラスでは
public class Product implements net.sf.hibernate.Lifecycle,Serializable {...
と記述します。
マッピングファイルからhbm2javaを使って永続クラスを自動生成する場合は、マッピングファイルに以下のように定義します。
<class name="sample.Product" table="PRODUCT" > <meta attribute="implements" inherit="false">net.sf.hibernate.Lifecycle</meta> <id name="id" type="java.lang.Integer" column="ID" > ...
lifecycleメソッドの実装
lifecycleインターフェースを実装したら、次にonSave()、onUpdate()、onDelete()、onLoad()の4つのlifecycleメソッドを実装します(※)。public boolean onSave(Session s) throws CallbackException { System.out.println("onSave"); return false; } public boolean onUpdate(Session s) throws CallbackException { System.out.println("onUpdate"); return false; } public boolean onDelete(Session s) throws CallbackException { System.out.println("onDelete"); return false; } public void onLoad(Session s, Serializable id) { System.out.println("onLoad"); return; }
※net.sf.hibernate.Sessionとnet.sf.hibernate.CallbackExceptionをインポートする必要があります。
これらのメソッドはそれぞれ以下のタイミングでコールされます。
メソッド | コールされるタイミング |
---|---|
onSave | 永続オブジェクトが挿入される直前にコールされる。 |
onUpdate | 永続オブジェクトが更新される前にコールされる。 |
onDelete | 永続オブジェクトが削除される前にコールされる。 |
onLoad | 永続オブジェクトがロードされた後にコールされる。 |
これらのメソッドに処理を記述すれば、コールされるタイミングでその処理が実行されます。
何もしたくない場合にはonLoad()ではそのまま戻し、onSave()、onUpdate()、onDelete()ではfalseを戻すようにします(trueを戻すと処理が中止されます)。
lifecycleインターフェース実装上の注意点
lifecycleメソッドの実装について
hbm2javaやHibernate Synchronizerでは、lifecycleインターフェースの実装は自動でやってくれますが、lifecycleメソッドの実装まではやってくれません。
したがって自動生成された永続クラスに手作業でメソッドを実装していかなければならず、コーディングに手間が掛かります。
また、hbm2javaを使用している場合、テーブル定義の変更などに伴って永続クラスを再作成すると、せっかく実装したlifecycleメソッドが上書きされて消えてしまうため注意が必要です。
(Hibernate Synchronizerを使用している場合は、永続クラスは1度作成されたら上書きされないためこのような問題は発生しません)
onUpdate()について
llifecycleインターフェースは一見データベースのトリガー風の便利な機能に思えますが、onUpdate()については少し注意が必要です。
onUpdate()は永続オブジェクトをLoadしてupdateする(読み込んでから更新する)場合にはコールされず、一時オブジェクトをupdateする(読み込まずに更新する)場合にのみコールされます。
したがって、普通に永続オブジェクトを取得して属性を変更して更新した時に何か処理を動かしたいと思ってもできないのです。
取得時にコールされるonLoad()を使えば代替可能なケースもありますが、そうでなければ別の実装方法を考えなければなりません。