はじめに
iBATISはSQLを利用することに注力したフレームワークです。高機能なO/Rマッピングフレームワークに比べて簡単に理解でき、レガシーなJDBC、ResultSetを使ったプログラミングから簡単に乗り換えられます。
特にSQLを多用する人には使いやすいフレームワークです。
この記事は前回の「iBATISを使ったO/RマッピングによるDBアクセスの実例」の続編です。前回はSELECT、INSERT、UPDATE、DELETEの基本的な記述方法についてサンプルを紹介しました。今回はSELECT文に注目し、検索結果のマッピングと動的SQLの記述方法について説明します。
iBATISの基本的な内容は、前回の記事を参考にしていただけると、分かりやすいと思います。
対象読者
- Javaの基本をマスターしている人
- SQL文を理解している人
必要な環境
iBATIS 2.3.0、J2SE 5.0の環境を前提に解説しています。データベースの選択は自由ですが、サンプルプログラムはHSQLDBで動作確認しています。
サンプルデータベース
本記事で使用しているデータベースは1つのテーブルを使用しています。
CREATE TABLE EMP ( EMPNO NUMERIC(4) NOT NULL, ENAME VARCHAR(10), JOB VARCHAR(9), MGR NUMERIC(4), HIREDATE DATE, SAL NUMERIC(7,2), COMM NUMERIC(7,2), DEPTNO NUMERIC(2) NOT NULL, CONSTRAINT PK_EMP PRIMARY KEY (EMPNO) );
検索結果を格納するクラス
検索結果を格納するBeanをあらかじめ用意しておきます。
package examples.dto; import java.sql.Date; public class Emp { private int empno; private String ename; private String job; private String manager; private Date hiredate; private float salary; private float commission; private int deptno; public int getEmpno() { return empno; } public void setEmpno(int empno) { this.empno = empno; } /* 中略 */ }
検索結果のマッピング
SQLを実行した結果は、そのままでは格納先のBeanにきちんと格納できないことがあります。例えば、検索結果の列名とBeanのプロパティ名が異なる場合には、「検索結果のfoo列をBeanのbarプロパティに格納する」というマッピングが必要になります。
また、「検索結果の値がNULL値のときは、Beanに999という値で格納する」という、ちょっとした条件判断によるマッピングが欲しい時もあります。
今回紹介するサンプルでは、表1のように検索結果からBeanのプロパティへのマッピングを行います。
検索結果の列 | 格納先Beanのプロパティ | 備考 |
MGR | manager(String) | |
SAL | salary(float) | |
COMM | commission(float) | NULLのときは0.0を格納 |
commission
プロパティはfloatで定義しているため、COMM列のデータがnullの場合は、0.0を格納する仕様とします。
SqlMap(SQLによるマッピング)
一番簡単な例は、SQL文でマッピングしてしまう方法です。SqlMapは次のようになります。
SQL文の別名とSQL関数を使ってマッピングします。
<!-- SQLでマッピングする記述方法。ifnullはDBMSの関数 --> <select id="allEmp1" resultClass="examples.dto.Emp"> SELECT EMPNO, ENAME, JOB, MGR as manager, HIREDATE, SAL as salary, ifnull(COMM, 0.0) as commission, DEPTNO FROM EMP </select>
SQLに慣れている場合はこの方法が直感的です。しかしSQL関数はRDBMSに依存した関数であるため、今回のサンプルの場合はHSQLDBに依存した書き方になってしまいます。
次に説明するresultMap
要素を使って記述すると、RDBMSに依存せずに記述することが可能です。
SqlMap(iBATISのresultMapによるマッピング)
resultMap
要素の記述で、検索結果→Beanのプロパティをマッピングします。
<!-- resultMapを記述してIBATISの機能でマッピングする方法DBに 依存しない記述 --> <resultMap id="rm1" class="examples.dto.Emp"> <result column="EMPNO" property="empno"/> <result column="ENAME" property="ename"/> <result column="JOB" property="job"/> <result column="MGR" property="manager"/> <result column="HIREDATE" property="hiredate"/> <result column="SAL" property="salary"/> <result column="COMM" property="commission" nullValue="0.0"/> <!-- NULLの時の指定 --> <result column="DEPTNO" property="deptno"/> </resultMap> <select id="allEmp2" resultMap="rm1"> SELECT * FROM EMP </select>
resultMap
は検索結果とJavaBeanをマッピングする定義です。この定義に"rm1"というIDを割り当てます。
EMPNO
列をempno
プロパティへ、...MGR
列をmanager
プロパティへとマッピングしています。またnullValue
属性で値を指定することで、NULL値の場合に格納する値を指定できます。
記述量は増えてしまいますが、特に難しい記述ではありません。<select id="allEmp2">
でのSELECT定義は、resultMap="rm1"
を参照しています。
実行プログラム
動作確認するサンプルは、次のようになります。
両方のマッピング方法で同じ結果が得られることが確認できます。
SqlMapClient sqlMap = MyAppSqlConfig.getSqlMapInstance(); /* * SQL文でマッピングに合うように結果を取得する。 * ・列名はasでDTOに合うように * ・null値は0に変換して取得 */ System.out.println("DBMSの関数ifnullを使用"); List<Emp> list1 = (List<Emp>)sqlMap.queryForList("allEmp1"); for (Emp e : list1){ System.out.println(e); } /* * iBATISのResultMapでマッピングする */ System.out.println("ResultMapを使ってibatisでマッピング"); List<Emp> list2 = (List<Emp>)sqlMap.queryForList("allEmp2"); for (Emp e : list2){ System.out.println(e); }