Hibernateより簡単とウワサの、iBATISをいじりつつ、実用のことを考えてみました。
iBATISの持っている機能リストから、想像しているだけなので、実際に検証しているわけではありません。
だから、変な話をしているかもしれません。
iBATISには、iBATIS Data Mapperと、iBATIS Data Access Objectというのがあるようですが、今回はSqlMapを使う前者を使っています。
ドメイン:テーブル:設定ファイルの関連
iBATISはSQLがすべてのベースにあります。
Hibernateでは、1ドメイン:1設定ファイルという具合ですが、iBATISではあまりこだわりがありません。
しかし、現実的なラインとしては、やはり1ドメイン:1設定ファイルが良いでしょう。
コトを簡単にするには、1ドメイン:1テーブルとなるでしょう。
iBATISではINSERT/UPDATE/DELETEでもSQLを書くことが前提で、こうした更新系のSQLは1テーブルを相手にすることになるので、やはり1ドメイン:1テーブル:1設定ファイルが望ましいと思います。
resultMapエレメントをきちんと設定する
iBATISでは、SELECTした時の結果をドメインに詰める際に、設定ファイルのselectエレメントのresultClassアトリビュートにドメインを書いておけばOKです。
カラム名とプロパティ名を自動的にマッチして、セットしてくれます。
カラム名とプロパティ名が違うのなら、カラム名をSQLのASで指定すれば良いのです。
しかし、私はresultMapエレメントで、selectエレメントと切り離してカラム名とプロパティ名のマッピングをしたほうが良いと思います。
resultMapエレメントが設定されていると、selectエレメントではresultClassアトリビュートの代わりに、resultMapアトリビュートを指定できるようになります。
1つのresultMapエレメントを、複数のselectエレメントから指定できます。つまり、マッピング設定の使い回しが出来るということです。
resultMapエレメントでテーブルとドメインをマッピングし、selectエレメントで投げるSQLのWHERE句あたりを指定するというのが、良さそうです。
但し、resultMapエレメントの効き目は、更新系SQLには及びません。
ドメインの関連をどうするか(参照系その1)
単純には、SQLを何度も実行してドメインを必要なだけ取得すればOKです。
しかし、それだけでは、上手くないでしょう。
例えば、Header-Detailや、マスタ参照といった、ドメインの関連が比較的強く、セットで取得することが決まりきっているような場合は、JOINして取得すれば良いのです。
Header側の設定ファイルで、selectエレメントでJOINするSQLを書き、resultMapエレメントを書けば、Detail側のドメインにも値を入れるように出来ます。
ドメインの関連をどうするか(参照系その2)
Header-Detailのような、トランザクションテーブル間の関連ならば、JOINで良いでしょう。
しかし、マスタ参照のようなトランザクションテーブル~マスタテーブルの関連や、マスタテーブル~マスタテーブルの関連の場合はどうでしょうか。
マスタは複数の設定ファイルから、JOIN対象にされるでしょうし、その度にマッピングを書くのは面倒です。(ここら辺がドメインに対してではなく、SQLに対して設定するiBATISの限界です。)
ならば、JOINするのはやめて、マスタ系ドメインは別々に取得すれば良いのです。
そうすると、当然、パフォーマンスの問題が出てくるでしょう。
iBATISではキャッシュの機能があります。それを活用しましょう。
マスタ系ドメインの取得のトリガーは、それを参照するドメイン内にあるマスタ系ドメインのgetterあたりが妥当ではないでしょうか?
それが嫌なら、Daoで何とかしましょう。
ドメインの関連をどうするか(更新系)
ストアドプロシージャを使わない以上は、1ドメイン:1テーブル毎に更新系のSQLを投げることになるでしょう。(iBATISではストアドプロシージャの呼び出しも出来るようです。)
Header-Detailのように、関連する複数のドメインオブジェクトを更新したい場合は、iBATISに頼るのはやめましょう。
iBATISに頼るのは1ドメイン:1テーブルの単位までに留めて、その上はDaoでやってあげましょう。(要するにDaoから複数回、SqlMapClientを使う。)
もしくは、Daoを使っているビジネスロジック(例えばService)でやっても良いでしょう。
その使い分けは、ドメイン間の関連の強さによると思います。(強ければDao、弱ければServiceとか。)
更新時の楽観ロックや監査証跡情報のセットは?
楽観ロックで使うバージョン番号や更新日時の取り扱いや、監査証跡用の更新者IDや更新日時といった情報のセットは、誰がやると良いでしょうか?
残念ながら、iBATISではその辺の機能は、なさそうです。
これは、Daoが頑張るしかなさそうです。
iBATISを使うと、Daoがそれなりに厚くなるのは覚悟した方が良さそうです。
その分だけ、iBATISでは永続化の仕掛けを、プログラマに任せることになります。
見通しが良くなってGood!と思うか、プログラマはアテにならないからヤダ!と思うかは、プロジェクト次第です。(後者だったら、SEがHibernateを使いこなして、プログラマをDaoのユーザにしてあげましょう。)
結局のところ
iBATISにしろ、Hibernateにしろ、ドメイン間に関連があるのは良いとして、その関連の強さをきちんと判断することが必要だと感じています。
関連を引けば引くほど、ビジネスロジックを書くのは簡単になりますが、永続化は面倒になります。
関連を引かなければ、その逆です。
だから、関連が強いのなら永続化フレームワークで担当し、関連が弱いのならDaoやビジネスロジックのレベルで、必要になる度に永続化フレームワークを使えば良いのです。(つまり、関連が依存になる。)
その見分けが面倒ですが、基準となるのはHeader-Detailとマスタ参照までが強い側だと思います。
あとは、Header-Detailを厳密に見極める必要があります。
下手をすると、何から何までHeader-Detailになりかねません。(親亀の背中に小亀…の無限ループ状態。)
その関連の強いドメインがいくつかまとまって、コンポーネントになり、そこに、そのコンポーネントにあるドメインを操作するサービスがくっ付いて、1つのコンポーネントが完成する…とかが、理想的かと。(これは妄想レベル。)