JPA2.0のタイプセーフCriteriaAPI感想とGoogle Collections Library
今までJPA2.0のCriteriaを試してみた感想とかそこらへんを書いていこうと思います。
結論から言うとCriteriaはJavaによるプログラミングを追求しているって感じじゃないのかなと*1。
ANDやORの使い方について
この感想を書くにはGoogle Collections Libraryで提供されているとあるAPIの事を取り上げねばならないのでまずはそちらについて。
Google Collections Libraryにはいろんな機能があるのですが今回関係するのはPredicate、Predicates、Iterablesといったクラスです。これらを使うとJavaでクロージャーを使う感じでListの絞り込みとか出来るようになります*2。ちなみにこのやり方はNext Generation Java Programing Styleの3番目に紹介されているやり方です。例えば下記はEmployeeのListから「IDが3より大きく且つAgeが18以上30以下もしくは部署がFinanceかIT」の従業員をコンソール出力するプログラムになります。(Employeeクラスは省略してます)
public void exec(){ //IDで絞り込むPredicate Predicate<Employee> byId = new Predicate<Employee>() { @Override public boolean apply(Employee input) { return input.getId() > 3; } }; //18歳以上で絞り込むPredicate Predicate<Employee> ge18 = new Predicate<Employee>() { @Override public boolean apply(Employee input) { return input.getAge() >= 18; } }; //30歳以下で絞り込むPredicate Predicate<Employee> le30 = new Predicate<Employee>() { @Override public boolean apply(Employee input) { return input.getAge() <= 30; } }; //部署がFinanceで絞り込むPredicate Predicate<Employee> finance = new Predicate<Employee>() { @Override public boolean apply(Employee input) { return input.getDepartment().equals("Finance"); } }; //部署がITで絞り込むPredicate Predicate<Employee> it = new Predicate<Employee>() { @Override public boolean apply(Employee input) { return input.getDepartment().equals("IT"); } }; //ここでIterables.filterとPredicatesのorやandを使って絞り込む! for(Employee emp:Iterables.filter(getList(),Predicates.and(byId,Predicates.or(Predicates.and(ge18,le30),finance,it)))){ System.out.println("emp = "+emp); } } private List<Employee> getList(){ List<Employee> list = new ArrayList<Employee>(); //いろんなEmployeeを作成してadd 省略・・・ return list; }
最後のforの部分においてIterablesとPredicatesをstatic importすると下記のように見やすくなるかと思います。
for(Employee emp:filter(getList(),and(byId,or(and(ge18,le30),finance,it)))){ System.out.println("emp = "+emp); }
また、これはListをプログラム上で作成してそれを絞り込んだわけですが、仮に同じ条件でDBのEMPLOYEEテーブルから取得する場合だとSQLは下記のようになります。
SELECT * FROM EMPLOYEE WHERE ID > 3 AND ( (AGE >=18 AND AGE <= 30) OR DEPARTMENT = 'Finance' OR DEPARTMENT = 'IT' )
Google Collections Libraryとの最大の違いはANDやORの位置です。そしてこの違いは以前のエントリーでも書いたJPA2.0のCriteria APIとSQLでのANDやORの位置の違いと同じです(Google Collections LibraryとCriteria APIが同じ)。また、Criteria APIにてequalやorやandの戻り値となるのはPredicateという型です。
不思議なもので自分がGoogle Collections Libraryを使用して上記のような絞り込みを試したときは始めてCriteria APIを使ったときのような違和感は感じませんでした。それでなんでなんだろうかと自分でいろいろ考えたんですが大きな理由は下記の2つになるんじゃないかという結論に達しました。
1番目は冗談としても2番目は重要だと思うんです。SQLではなくJavaのプログラミングとして考えると確かにandやorの使い方はすんなり頭に入ったわけです。JSRの中の人がどれほどGoogle Collections Libraryを意識していたのか、もしくはそれ以前からそういうプログラミングスタイルが欧米では珍しくなかったのかは不明ですがこのANDとORの使い方に関してGoogle Collections LibraryとCriteria APIが同じだという事実はCriteria APIを使うもしくは理解する上では重要なのではないでしょうか。
また、そもそもJPAはJavaにおけるO/Rマッパーの標準APIです。O/Rマッパーとは本来の意味で言うとオブジェクト指向とリレーショナルなデータ管理指向との間におけるインピーダンスミスマッチを解決するためのものです。その点で考えるとJPAのCriteria APIがSQL寄りではなくJava寄りになったのは当然といえば当然なのかもしれません。
Criteria APIを使用することで生産性は上がるのか??
これは正直わかりませんww自分は結構慣れたので動的なSQL構築なんかはCriteriaはかなり良いと思います。ただ、id:da-yoshiさんの
GlassFish V3 b67を使ってJava Persistence 2.0を試す - TYAGE EMOTION
にて最後の方に書かれているように一時変数が多くなりがちです*3。あと、id:trygunさんのこちらのエントリー
2009-10-14
にて後輩さんが言うことはもっともだと思います。