学習用ORマッパー「EzJDBC」の作成 その4
昨日の続きです。
学習用ORマッパー「EzJDBC」の作成 その1(2008-12-08 - T.RYoken がんばる日記 / TryGun blog)
学習用ORマッパー「EzJDBC」の作成 その2(2008-12-09 - T.RYoken がんばる日記 / TryGun blog)
学習用ORマッパー「EzJDBC」の作成 その3(2008-12-10 - T.RYoken がんばる日記 / TryGun blog)
最後に…
EzJDBCは、Seasarの「S2JDBC」に良く似ています。
よく似ているのは当たり前で、EzJDBCは「S2JDBC」をお手本にして、開発しました(実装は別物)。
*お手本にした内容は、「流れるようなインターフェース」です。
* EzJDBCは、S2JDBCをリスペクトしています。『良いものはマネしろ』の精神です。
何故S2JDBCを利用しなかったのでしょうか?
理由は、S2JDBCが発表される前に、EzJDBCのコアな機能にあたるEzDaoが既にあったためです。
また当初、S2JDBCは、タイプセーフではなかった事も理由に上げられます。
でも、最大の理由は、JAVAのバージョンの問題です。「JAVA 1.4」でも利用したかったのです。
追記 : 現在は、S2JDBCの「SQL自動生成」はタイプセーフになります。
http://jfut.featia.net/diary/20081008.html
素のS2JDBCの利用方法は、下記のような感じでタイプセーフにはなっていませんでした。
S2JDBCを素で利用した時の例
Listresults = jdbcManager.from(Customer.class)
.join("order")
.where("code = ?", "T%")
.orderBy("code")
.getResultList();
上記ソースの内容を簡単に説明します。
ソースを見て分かる通り、join, where, orderByメソッドのシグニチャが全て文字列であるため、結合先のテーブル名や項目名がタイプセーフになっていません。
1. fromメソッド
from(Customer.class)メソッドにより、"メインテーブル"の指定と"参照結果を格納するエンティティ"の
両方を指定したことになります。2. joinメソッド
join("order")メソッドは、CUSTOMERテーブルとORDERテーブルを
JOINすることを指定しています。JOINの結合条件(ON)は、Customer.classの「order」
プロパティーにアノテーションを利用して記述します。3. whereメソッド
where("code LIKE ?", "T%")メソッドは、
抽出条件を指定するメソッドです。第一引数はSQLの条件式で第二引数が比較値になります。第一引数の
「"code LIKE ?"」に記述されている「"code"」は
テーブルの項目名「CODE」をキャメル記法で記述しまものです。4. orderByメソッド
orderBy("code")メソッドは、ソートをあらわしており、シグニチャとして
受け渡されている「"code"」は抽出条件と同様で、「CODE」をキャメル記法です。5. getResultListメソッド
SQLを発行し結果を取得するメソッドです。
そのため、テーブルに変更があった場合の修正が煩雑になります。修正もれが発生する可能性が出てくるわけです。例えば、CUSTOMERテーブルの項目「CODE」を「CUSTOMER_CODE」に変更することになったとします。
変更対象となるCUSTOMERテーブルの「CODE」は、whereメソッドとorderByメソッドのシグニチャとして文字列で指定されているため、「CODE」という項目がテーブルからなくなっても、上記JAVAソースはエラーになってくれません。
よって、全ソースから「code」を利用している箇所を検索し、「customrtCode」に修正する作業が発生してしまうのです。これはちょっと頂けないなぁって、思っていたところ、S2JDBCでもタイプセーフを可能にするscaffoldを作成したようです。
その結果が、上記URLに記述されているのですが、個人的感想を言わせてもらうと「分かりにく〜い」って感じです。
URLの例では、何がなんだかわからないので、S2JDBCを素で利用した時の例をタイプセーフにし場合を例に見てみてみましょう。
S2JDBCでタイプセーフを実現した例
確かに、比較値("T%")以外は、全てメソッドになっているので、タイプセーフではありますが …
Listresults = select()
.leftOuterJoin(order())
.where(like(code(), "T%"))
.orderBy(code ())
.getResultList();
個人的には、全てをメソッドで表現するのは、ちょっと分かりづらいかなぁっと感じました。
上記ソースの内容を簡単に説明します。
タイプセーフにする為に、全ての情報をメソッドで、表現しようとしたため、括弧が多くて見ずらい印象を受けます。上記のソースぐらいであれば、何とか解読することは可能かもしれませんが、テーブルの結合や抽出条件が多くなった場合は、かなり辛くなりそうです。
1. selectメソッド
select()メソッドにはSUPERクラスで実装されているメソッドで、SUPERクラスでは下記ソースが実装されて
います。jdbcManager.from(Customer.class)
2. leftOuterJoinメソッド
leftOuterJoin(order())メソッドは、CUSTOMERテーブルとORDERテーブルをJOINすることを指定しています。
シグニチャのorder()メソッドで、JOIN先のテーブル名が「ORDER」であることを表しています。
シグニチャのORDER()メソッドも親クラスに実装されたメソッドです。JOINの結合条件(ON)は、Customer.classの
「ORDER」プロパティーにアノテーションを利用して記述します。3. whereメソッド
where(like(code(), "T%"))メソッドは、抽出条件を指定するメソッドです。
シグニチャのlike()メソッドで、比較条件式が「LIKE」であることをあらわしています。
likeメソッドの第一引数に記述されている「code()」は、CUSTOMERテーブルの項目「CODE」を表しています。4. orderByメソッド
orderBy(name())メソッドは、ソートを指定するメソッドです。
シグニチャの「code()」は、CUSTOMERテーブルの項目「CODE」を表しています。5. getResultListメソッド
SQLを発行し結果を取得するメソッドです。
では、EzJDBCで同じ内容を実装するとどうなるのでしょうか?
EzJDBCで同じ処理を記述するとこうなります。
可読性の高さが分かると思います。この可読性の秘密は、以下のルールに基づきます。
// メインテーブルのCUSTOMERテーブル情報インスタンスを生成します。
CUSTOMER _CUSTOMER = new CUSTOMER();
// EzJDBCインスタンスを生成し、結果を取得します。
List result = new EzJDBC().from(_CUSTOMER._ORDER)
.where(_CUSTOMER.CODE.likeBegin("T"))
.orderBy()
.asc(_CUSTOMER.CODE)
.find(Customer.class);
1.「_(アンダースコア)有り」の名称は、テーブル名 … 「_CUSTOMER」, 「_ORDER」
2.「_(アンダースコア)無し」の名称は、フィールド名 … 「CODE」
3.「メソッド」は、比較演算式 … 「likeBegin(...)」
EzJDBCの自動生成機能を利用していれば、仮にCUSTOMERテーブルのCODE項目の型を「文字」から「数値」に変更した場合でも、上記ソースがエラーになって問題を知らせてくれます。
エラーの内容は「CODEは数値型だから、likeBeginメソッドは使えないよー!」ってなってくれるのです。