SeasarのO/RマッピングツールS2Dao:Seaser Projectの全貌を探る(5)(2/2 ページ)
Seasar(シーサー)は、国内のコミュニティ「The Seasar Project」によって開発が行われているオープンソースプロダクトだ。DI+AOPコンテナとして評価が高いSeasarV2は、J2EE開発の現場にも影響力を持ち始めた。例えば電通国際情報サービスがSeasar Projectを正式に支援することを表明し、2005年6月からは同社による商用サポートサービスが開始されている。本連載では、同プロジェクトの代表的なプロダクトを紹介していく。(編集局)
SQLファイルの内容を実行させる
前ページで新しいカテゴリを追加する処理を行った際、SQL文を自動生成させて実行したため、IDカラムの値を保存しようとしてしまうことになってしまいました。それでも先ほどの処理はうまく実行できましたが、いつも自動生成されるSQL文だけで必要とする処理ができるとは限りません。
そこで、開発者がカスタマイズしたSQL文を決められた形式の名称を持つファイル(SQLファイル)に保存しておくと、その内容を読み込んでデータベースに対して実行してくれる機能を用いて、新しいカテゴリを追加する処理を行うSQLをカスタマイズしてみます。
SQLファイルには、リスト7のように書き込んでおきます。/*〜*/の部分はSQLコメントという機能で、ここではcategory変数のnameプロパティの値を表しています。その次に記述されている'カテゴリ名称'は、仮にこの値が設定されていない場合のデフォルト値です。
これに伴って、リスト1には新たなアノテーションをBEANアノテーションのすぐ次の行に追加します(リスト8)。これはARGSアノテーションというもので、リスト7のSQLコメントに記述されている変数名にinsertCategoryメソッドの引数の値を割り当てる(バインドする)ことを示しています。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
SQLファイルの命名規則
SQLファイルは、必ず“インターフェイス名またはクラス名_メソッド名.sql”という名称で作成します。そしてこのファイルは、ファイル名に記したインターフェイスまたはクラスと同じ階層のディレクトリにデプロイします。例えばリスト1(CategoryDao.java)はmyfirst.daoというパッケージ名ですから、リスト7もmyfirst\dao\CategoryDao_insertCategory.sqlにデプロイされることになります。
また、SQLファイルのファイル名は、データベースの種類ごとに分けることも可能です。この場合は拡張子の直前に“_データベースの種類を表す接尾辞”を付けます。例えばリスト7をMySQL用に限定する場合は、ファイル名をCategoryDao_insertCategory_mysql.sqlとします。
SQLコメントの種類
EntityManagerのメソッドには、find()、findArray()、findBean()、findObject()の4種類があります。これらのメソッドの第1引数は、自動生成されるSQL文に付け足すWHERE句またはORDER BY句です。WHERE句の場合はこの引数にWHEREを記述する必要はないのですが、最初からORDER BY句を記述する場合はORDER BYを省略することはできません。
第2引数以降は、第1引数に記述されている“?”(パラメータマーカ)に割り当てる値を設定します。これらの引数は3つまで(つまり第4引数まで)個別に設定するか、第2引数で配列により設定する方法とがあります。find()メソッドで例を挙げると以下のようになります。
public List find(String query);
public List find(String query, Object arg1);
public List find(String query, Object arg1, Object arg2);
public List find(String query, Object arg1, Object arg2, Object arg3);
public List find(String query, Object[] args);
戻り値は、それぞれのメソッドによって異なり、これが各メソッドの役割を表しています。
find()メソッド …… List (要素はエンティティオブジェクト)
findArray()メソッド …… Object[] (要素はエンティティオブジェクト)
findBean()メソッド …… Object (エンティティオブジェクト)
fintObject()メソッド …… Object (スカラー値など)
詳細はS2Daoのドキュメント(http://www.seasar.org/s2dao.html)を参照してください。
SQLコメントは、SQLファイルやSQLアノテーションに記述するときに、“/*〜*/”で囲んで変数名や制御文などを記述するものです。“/*”の次に空白があるとSQLコメントとしては扱われず、何の処理も行わないコメントとして扱われますので注意してください。
SQLコメントには、上記のような変数に値を割り当てるためのものだけでなく、以下に示す種類のものがあります。詳細はS2Daoのドキュメント(http://www.seasar.org/s2dao.html)を参照してください。
- バインド変数コメント(/*変数名.プロパティ名*/ :使用例は上記)
- 埋め込み変数コメント(/*$変数名.プロパティ*/)
両者はともにARGSアノテーションで設定された変数の値をここに割り当てます。ただし、変数名の先頭に$が付いていない場合は、オブジェクトの値を文字列に直したもの(toStringメソッドを実行したもの)が割り当てられます。先頭に$が付いていればオブジェクトの値そのものが割り当てられます。
この直後にリテラルの文字列が記述されているときは、その値がデフォルトになります。
- IFコメント(/*IF 条件式*/リテラル/*END*/)
条件式の値に応じてリテラルをSQL文に含めるかどうかが決まります。 - BEGINコメント(/*BEGIN*/WHERE句/*END*/)
WHERE句の中に複数のIFコメントを用いたとき、そのIFコメントでいずれもリテラルを出力しないときにはWHERE句自体を実行しません。どれか1つのIFコメントでリテラルが出力されることになったら、WHERE句は実行されます。
EntityManagerによる検索処理
EntityManagerとは、S2Daoのorg.seasar.dao.EntityManagerインターフェイスを実装したオブジェクトのことで、検索処理を行うfind〜で始まるメソッドを多数実装しています。これらのメソッドの内部では、SELECT文の自動生成が行われるため、Javaソースコードをシンプルにすることができます。なお、EntityManagerでは更新用のメソッドは用意されていません。
こうした処理を行うには、リスト9のように、必ずorg.seasar.dao.impl.AbstractDaoクラスを継承し、コンストラクタにorg.seasar.dao.DaoMetaDataFactoryオブジェクトが設定されるようにしなくてはなりません。このクラスの中でEntityManagerを用いるときはgetEntityManager()メソッドを記述します。
この中でEntityManagerのfindメソッドの引数には“ORDER BY id”と設定されていますが、これは自動生成されたSELECT文の後にこれを付け足してデータベースで実行させることを意味します。そしてfindBean()メソッドの第1引数“id = ?”は、自動生成したSQLのWHERE句となるもので、その次の引数の値を“?”の部分に割り当てて(バインドして)からSQL文をデータベースで実行させます。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
EntityManagerのメソッドの種類
EntityManagerのメソッドには、find()、findArray()、findBean()、findObject()の4種類があります。これらのメソッドの第1引数は、自動生成されるSQL文に付け足すWHERE句またはORDER BY句です。WHERE句の場合はこの引数にWHEREを記述する必要はないのですが、最初からORDER BY句を記述する場合はORDER BYを省略することはできません。
第2引数以降は、第1引数に記述されている“?”(パラメータマーカ)に割り当てる値を設定します。これらの引数は3つまで(つまり第4引数まで)個別に設定するか、第2引数で配列により設定する方法とがあります。find()メソッドで例を挙げると以下のようになります。
public List find(String query);
public List find(String query, Object arg1);
public List find(String query, Object arg1, Object arg2);
public List find(String query, Object arg1, Object arg2, Object arg3);
public List find(String query, Object[] args);
戻り値は、それぞれのメソッドによって異なり、これが各メソッドの役割を表しています。
find()メソッド …… List (要素はエンティティオブジェクト)
findArray()メソッド …… Object[] (要素はエンティティオブジェクト)
findBean()メソッド …… Object (エンティティオブジェクト)
fintObject()メソッド …… Object (スカラー値など)
詳細はS2Daoのドキュメント(http://www.seasar.org/s2dao.html)を参照してください。
n:1マッピングによるリレーションの設定
categoryテーブルのidカラムの値は、accountテーブルのid_catカラムの値と関連付けられ、あるaccountデータが属するカテゴリを示しています。こうしたときはN:1マッピングの設定を行うと、両方のテーブルに対してLEFT OUTER JOINを行うことができます。前回のリスト12で示したAccount.javaに少し変更を加え、この機能を利用してデータの一覧を取得してみましょう。
Account.javaには、S2Daoのアノテーションをいくつか追加します。その中でn:1マッピングを行うための設定はRELNO定数とRELKEYS定数という2つです。これらについて説明します。
RELNO定数はマッピングの際に用いる番号のことで、マッピングされるテーブルを数値で表したものです。この数値は自動生成されるSQL文で用いられます。実行例は後述します。RELKEYS定数は関連付けられるカラムを“:”で仕切って表したものです。リスト10で“ID_CAT:ID”とあるのは、accountテーブルのid_catカラムの値とcategoryテーブルのidカラムの値とが関連付けられることを表します。関連付ける相手のテーブルは、テーブル(表1)の作成時に外部キー制約が付けられた相手ということになります。
フィールド | データ型 | 制約 |
---|---|---|
id | INTEGER | PRIMARY KEY |
name | VARCHAR(100) | UNIQUE |
フィールド | データ型 | 制約 |
---|---|---|
id | INTEGER | PRIMARY KEY |
id_cat | INTEGER | FOREIGN KEY REFERENCEScategory(id) |
title | VARCHAR(200) | NOT NULL |
amount | INTEGER | NOT NULL |
memo | TEXT | |
date_create | DATE | NOT NULL |
date_modified | DATE | NOT NULL |
accountテーブルにアクセスするためのDAOインターフェイスをリスト11のように作成し、accountテーブルのデータを取得してみます。これを用いてデータベースにアクセスする処理をリスト12のように作成して実行するとリスト13が出力されます。DEBUGで始まる行がS2Daoによる出力で、Accountで始まる行が、データベースから取得したAccountオブジェクトのプロパティの値を表しています。
このとき自動生成されたSQLにLEFT OUTER JOINが含まれていることを確認してください。そしてAccountクラスのcategoryプロパティにCategoryクラスのプロパティの値がid、nameともに含まれていることも一緒に確認してみてください。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
最後に、accountテーブルに保存されているデータのうち、同じカテゴリIDを持つもののみを取得する例を紹介しましょう。このときは、データを取得する条件を設定するためのクラス(リスト14)を作成し、カテゴリIDが関連付けられるカラム(id_0)をCOLUMNアノテーションで設定しておきます。なぜid_0という名称なのかというと、リスト13で実行されている自動生成されたSQL文に“category.id AS id_0”という部分があるからです。
あとはリスト11のgetAccountByCategory()メソッドを実行すれば完了です。リスト16で実行されたSQL文と実行結果とを確認してみてください。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
今回はS2プロダクトのうち、O/Rマッピングを行うS2Daoを紹介しました。XMLの設定を使わないなど、ユニークな特長を持っており、開発を効率化させるための仕組みがいろいろと用意されていることが分かりました。S2本体と一緒に使うことでその仕組みを存分に生かすことができますので、S2によるアプリケーションを開発する際にはS2Daoを使うことも検討してみてください。
Copyright © ITmedia, Inc. All Rights Reserved.