まずはselect

機会がなかったので機能を読んで追っていただけで実は使ったことがなかった。ここらへんでちょっと使いはじめてみようと思う。まぁ機会がないのは変わらないけど。
seasar.orgにはすばらしいマニュアルがあるが、S2Daoの機能がフルに解説されていて、僕としては難しく感じてしまう。なので、まずは一番シンプルにselectを表現したらどうなるのか辺りから少しづつ試してみようと思う。
※ DBはHSQLDB。あとはeclipse上でS2本体、S2DaoCVSからチェックアウトして、参照して使うのが簡単。

作るもの

書籍の情報を持ったBOOKテーブルから、書籍のIDを指定して情報を取り出すことを考える。SQL文でいうとselect * from BOOK where id = ?という感じの処理ができるイメージ。

用意するもの

事前に用意するのはテーブル。あとはDAOとEntityとdicon、それと実際に動かしてみるためにDAOを使うクラスの4つ。SQL文は書かないで、S2DaoSQL文を自動生成する機能を利用してみる。

テーブル

書籍の情報を持ったBOOKテーブルを作る。書籍IDと書籍名を持っているだけの、実際には役に立たないもの。データは何でもOKなので適当に入れておく。

CREATE TABLE BOOK (
       id INTEGER NOT NULL IDENTITY PRIMARY KEY
     , name VARCHAR(50) NOT NULL
);
INSERT INTO BOOK(NAME) VALUES('Seasar2入門(仮)');

DAO

Entity(Bean)をテーブルから取得するためのDAOのinterfaceを作る。

package examples.s2dao.book.dao;

import examples.s2dao.book.entity.Book;


public interface BookDao {
    // Beanの関連付け
    public static final Class BEAN = Book.class;
    // 書籍取得の検索条件
    public static final String getBook_QUERY = "id = ?";
    
    public Book getBook(int id);
}

最低限必要なアノテーションのみ記述すると、これだけで済んでしまうようだ。このDAOが処理するBeanと、getBookで取得する際の検索条件だけでOK。getBookの引数は1つなので、ARGSアノテーションも要らない。

Entity(Bean)

BOOKテーブルのレコードの値を格納するためのBeanを作る。

package examples.s2dao.book.entity;

import java.io.Serializable;


public class Book implements Serializable {
    private int id;
    private String name;
    
    public void setId(int id) {
        this.id = id;
    }
    
    public int getId() {
        return id;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    
    public String toString() {  
        return new StringBuffer()
            .append("id: ").append(id).append(", ")
            .append("name: ").append(name)
            .toString();
    }
}

これには何もアノテーションを記述していない。クラス名がテーブル名と同じなのでTABLEアノテーションは省略できるし、プロパティ名もBOOKテーブルのカラムと同じ名前なのでCOLUMNアノテーションも省略できてしまう。

dicon

DAOのインターフェースを登録する。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
	"http://www.seasar.org/dtd/components21.dtd">

<components>
    <include path="dao.dicon"/>
    
    <component class="examples.s2dao.book.dao.BookDao">
        <aspect>dao.interceptor</aspect>
    </component>
</components>

上で作ったBookDaoインターフェースをコンポーネントとして登録する。それに対して、S2Daoのインターセプタをで指定してやる。これでBookDaoインターフェースにS2Daoの魂が織り込まれ、実装クラスを作り出してくれる。

DAOを使うクラス

ここまでで、S2Daoを使うものはすべてそろった。あとは実際に動かしてみるために、DAOを使うクラスを作る。

package examples.s2dao.book;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

import examples.s2dao.book.dao.BookDao;


public class BookClient {
    private static final String PATH = "examples/s2dao/book/dao/BookDao.dicon";

    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            BookDao dao = (BookDao) container.getComponent(BookDao.class);
            System.out.println(dao.getBook(0));
        } finally {
            container.destroy();
        }
    }
}

おなじみのコンポーネントを取得するコード。dao.getBook()で書籍IDが0のレコードを取得している。

動かす

ちゃんと動いた模様。

DEBUG 2005-04-09 13:43:10,240 [main] 物理的なコネクションを取得しました
DEBUG 2005-04-09 13:43:10,240 [main] 論理的なコネクションを取得しました
DEBUG 2005-04-09 13:43:10,641 [main] 論理的なコネクションを閉じました
DEBUG 2005-04-09 13:43:10,681 [main] SELECT Book.name, Book.id FROM Book WHERE id = 0
DEBUG 2005-04-09 13:43:10,681 [main] 論理的なコネクションを取得しました
DEBUG 2005-04-09 13:43:10,711 [main] 論理的なコネクションを閉じました
id: 0, name: Seasar2入門(仮)
DEBUG 2005-04-09 13:43:10,721 [main] 物理的なコネクションを閉じました

S2Daoが自動的に生成したSQL文に、QUERYアノテーションで指定した検索条件が組み込まれていて、期待の書籍、「Seasar2入門(仮)」が取得できている。

まとめ

欲しいデータの形をBeanで用意してやって、あとはそれをどう扱うかをDAOインターフェースに宣言してあげるだけ。すばらしいの一言。
省きに省くと、シンプルになることが良くわかる。ただ、実際のシーンではこんなに単純なことはほとんどないかもしれないが、逆にカラム名とかをあらかじめ考慮しておくことができれば、作るのを楽にすることができそう。いやもう、S2Daoを使う時点で十分楽だけどね。