S2JDBCで、WHERE句以降を動的に付与して実行したい

取得するカラムは一緒だけども、検索条件はいろいろ変わる…
こんな時、WHERE句以降をSQL実行時に自由に指定出来るようなSelectHandlerがあれば、コンポーネントが増えなくて済みそうです。


(メモ)そういったハンドラがあるのか後で調べる。(今晩の宿題)

見当たらないので、BasicSelectHandlerを拡張してみました。
けど、、、これだとマルチスレッドでダメ(同時にexecuteを呼ぶと、SQL文が後から呼ばれたものとして両方実行されてしまう可能性あり)なので、マルチスレッドで使われる場合には、排他かける必要があります。

import org.seasar.extension.jdbc.impl.BasicSelectHandler;
import org.seasar.framework.exception.SQLRuntimeException;

public class AppendSelectHandler extends BasicSelectHandler {

    private String baseSql;

    public Object execute(String append, Object[] args)
            throws SQLRuntimeException {
        return execute(append, args, getArgTypes(args));
    }

    public Object execute(String append, Object[] args, Class[] argTypes)
            throws SQLRuntimeException {
        super.setSql(baseSql + " " + append);
        return super.execute(args, argTypes);
    }

    /**
     * @see org.seasar.extension.jdbc.impl.BasicHandler#setSql(java.lang.String)
     */
    public void setSql(String sql) {
        baseSql = sql;
        super.setSql(sql);
    }

    /**
     * @see org.seasar.extension.jdbc.impl.BasicSelectHandler#execute(
     *      java.lang.Object[], java.lang.Class[])
     */
    public Object execute(Object[] args, Class[] argTypes)
            throws SQLRuntimeException {
        super.setSql(baseSql);
        return super.execute(args, argTypes);
    }
}

setSqlをオーバライドして、diconファイルにて設定したSQLを、基本となるSQL(baseSql)として、インスタンス変数に保持します。
そして、SQL実行時(execute)にて、基本となるSQLと追加で指定されたSQLを結合し、実際に実行されるSQLとして設定(super.setSql)します。
追加するSQLを指定できるよう、下記のメソッドを追加してます。

  • public Object execute(String append, Object[] args)
  • public Object execute(String append, Object[] args, Class[] argTypes)

diconファイルにて、上記クラスをハンドラとして指定します。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
  <include path="j2ee.dicon"/>
  <component name="selectBeanListHandler"
    class="AppendSelectHandler">
    <property name="sql">
      "SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno FROM emp"
    </property>
    <property name="resultSetHandler">
      <component class="org.seasar.extension.jdbc.impl.BeanListResultSetHandler">
        <arg>@examples.jdbc.Employee@class</arg>
      </component>
    </property>
  </component>
</components>

実行は、下記のような感じになります。

mport java.util.List;

import org.seasar.extension.jdbc.SelectHandler;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

public class SelectBeanListClient {

    private static final String PATH = "SelectBeanList.dicon";

    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            AppendSelectHandler handler = (AppendSelectHandler) container
                    .getComponent("selectBeanListHandler");

            // SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno
            //     FROM emp
            //     WHERE empno = 100
            List result = (List) handler.execute(
                                         "WHERE empno = ?",
                                         new Object[]{new Integer(100)});
            for (int i = 0; i < result.size(); ++i) {
                System.out.println(result.get(i));
            }

            // SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno
            //     FROM emp
            //     ORDER BY empno
            result = (List) handler.execute("ORDER BY empno", null});
            for (int i = 0; i < result.size(); ++i) {
                System.out.println(result.get(i));
            }

            // SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno
            //     FROM emp
            result = (List) handler.execute(null);
            for (int i = 0; i < result.size(); ++i) {
                System.out.println(result.get(i));
            }
        } finally {
            container.destroy();
        }
    }
}