ひがやすを技術ブログ

電通国際情報サービスのプログラマ

S2Dao

今日でGWはおわり。うちの会社は品川へ引っ越すため、
4/30が休日になった代わりに、5/5から出社になります。
S2DaoではSQL開発者とJava開発者がきちんと分業する仕組みを
提供します。
SQL*Plusなどでも直接実行できるし、
Javaのオブジェクトとのマッピングも同時にできる2Way SQL
いうのがコンセプトになります。
まずは、サンプルとなるDaoのインターフェースから。


class EmployeeDao {
List getEmployees();
Employee getEmployee(Integer empno);
List getEmployeesByJobDeptno(String job, Integer deptno);
int updateEmployee(Employee employee);
}
次は、このインターフェースのためのS2Daoの定義。

<s2dao>
<select name="getEmployees">
<handler class="BeanListResultSetHandler">
<property name="beanClass">examples.s2dao.Employee.class
</handler>
SELECT * FROM emp
</select>
<select name="getEmployee" args="empno">
<handler class="BeanResultSetHandler">
<property name="beanClass">examples.s2dao.Employee.class
</handler>
SELECT * FROM emp WHERE empno = /*S2 ?{empno}*/7788/**/
</select>
<select name="getEmployeesByJobDeptno" args="job, deptno">
<handler class="BeanListResultSetHandler">
<property name="beanClass">examples.s2dao.Employee.class
</handler>
SELECT * FROM emp
/*S2*/WHERE
/*S2 AND(job is not null) job = ?{job}*/job = 'CLERK'/**/
/*S2 AND(deptno is not null) deptno = ?{deptno}*/AND deptno = 30/**/
/**/
</select>
<update name="updateEmployee" args="employee">
INSERT INTO emp(...) values(?{employee.empno}, ...)
</update>
</s2dao>
最初のgetEmployeesの定義を見てください。selectタグの子要素handlerで
S2JDBCのResultSetHandlerを指定します。
次にgetEmployeeの定義を見てください。インターフェースにあった引数の
名前をargsで指定しています。引数が複数ある場合は、カンマで区切ります。
#リフレクションで引数の名前まで取れたらいいのに。
/*S2 ?{empno}*/7788/**/が注目すべきポイントです。
SQL*Plusなどのツールで実行するときには、コメント部分がなくなり7788と
評価されますが、S2Daoとして実行するときには、?{empno}に置き換えられ
バインド変数として引数のempnoを埋め込むという意味になります。
3つめはgetEmployeesByJobDeptnoです。
/*S2*/WHERE
/*S2 AND(job is not null) job = ?{job}*/job = 'CLERK'/**/
/*S2 AND(deptno is not null) deptno = ?{deptno}*/AND deptno = 30/**/
/**/
が注目すべきポイント。Sqletのような動的なSQL文の組み立てです。
http://homepage3.nifty.com/seasar/doc/nazuna-sqlet.html#SelectWhere
jobもdeptnoもnullの場合は、SELECT * FROM emp
jobはnot null、deptnoがnullの場合は、SELECT * FROM emp WHERE job = ?{job}
jobはnull、deptnoがnot nullの場合は、SELECT * FROM emp WHERE deptno = ?{deptno}
job, deptnoともnot nullの場合は、SELECT * FROM emp WHERE job = ?{job} AND deptno = ?{deptno}
のようになります。
あとはこれをInterceptorでインターフェースとXMLを結び付けます。

<component class="examples.s2dao.EmployeeDao">
<aspect>
<component class="org.seasar.dao.interceptors.S2DaoInterceptor">
<property name="path">examples/s2dao/EmployeeDao.xml
</component>
</aspect>
</component>
Javaのロジックは一切ありませんが、使う側にとっては、
Javaの実装クラスが存在しているように見えることでしょう。
AOPの有用な使い方の1つだと思ってます。
もちろん、INNER, OUTER JOINは自由自在です。