学習用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を素で利用した時の例


List results = jdbcManager.from(Customer.class)
                       .join("order")
                       .where("code = ?", "T%")
                       .orderBy("code")
                       .getResultList();

上記ソースの内容を簡単に説明します。


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を発行し結果を取得するメソッドです。

ソースを見て分かる通り、join, where, orderByメソッドのシグニチャが全て文字列であるため、結合先のテーブル名や項目名がタイプセーフになっていません。
そのため、テーブルに変更があった場合の修正が煩雑になります。修正もれが発生する可能性が出てくるわけです。例えば、CUSTOMERテーブルの項目「CODE」を「CUSTOMER_CODE」に変更することになったとします。


変更対象となるCUSTOMERテーブルの「CODE」は、whereメソッドとorderByメソッドのシグニチャとして文字列で指定されているため、「CODE」という項目がテーブルからなくなっても、上記JAVAソースはエラーになってくれません。


よって、全ソースから「code」を利用している箇所を検索し、「customrtCode」に修正する作業が発生してしまうのです。これはちょっと頂けないなぁって、思っていたところ、S2JDBCでもタイプセーフを可能にするscaffoldを作成したようです。


その結果が、上記URLに記述されているのですが、個人的感想を言わせてもらうと「分かりにく〜い」って感じです。


URLの例では、何がなんだかわからないので、S2JDBCを素で利用した時の例をタイプセーフにし場合を例に見てみてみましょう。


S2JDBCでタイプセーフを実現した例

List results = select()
              .leftOuterJoin(order())
              .where(like(code(), "T%"))
              .orderBy(code ())
              .getResultList();
確かに、比較値("T%")以外は、全てメソッドになっているので、タイプセーフではありますが … 
個人的には、全てをメソッドで表現するのは、ちょっと分かりづらいかなぁっと感じました。
上記ソースの内容を簡単に説明します。

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メソッドは使えないよー!」ってなってくれるのです。