設定ファイルゼロのORマッパー BeanKeeper

BeanKeeper

BeanKeeper はシンプルなORマッパーです。設定ファイルを書く必要がなく、利用方法も明快です。本家は http://beankeeper.netmind.hu/index.php で現在のメジャーリリースバージョンは 2.6 となっています。
特徴として以下が挙げられています。

  • 利用方法が簡素で、特別なツールも必要なく数分で使い始められる
  • 設定ゼロ
  • 小さなフットプリント
  • PostgreSQLMySQLHSQLDBOracle をサポート
  • 多様性の完全なサポート
  • シンプルで読みやすいクエリ言語
  • List、Map、Set などの Collections によるリレーションを扱うことができる
  • オブジェクト間の参照や自己参照、循環参照を扱うことができる
  • 遅延読み込みのサポート
  • Historical 検索が可能
  • 複数オブジェクトからの "View" 選択
  • 結果リストのキャッシュ
  • 分散型のスケーラブルオペレーション
  • 構造的、多様的ロックのサポート

セットアップ

今回は 2010/03/17 リリースの beankeeper-2.6.3.tar.gz を使用しました。ソースとpom.xml の配布なので、Maven で以下のように jar 作っておきましょう。

mvn package


なお、今回は HSQLDB 1.8.1 を使用します。現時点では HSQLDB 2系は利用できませんでした。

必要なライブラリは以下となります。

  • log4j
  • commons-configuration
  • commons-lang
  • commons-collctions
  • commons-logging
  • hsqldb-1.8.1.3
  • beankeeper-2.6.3

log4j.properties を以下の様に作成しておきます。

log4j.rootLogger=INFO,stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d{HH:mm:ss,SSS} %m%n

エンティテイの準備

利用するエンティテイを作成します。

package etc9.domain;

import java.util.Date;

public class Book {
    private String title;
    private Author author;
    private Date releaseDate;

    public Book() {
    }
    public Book(String title, Author author, Date releaseDate) {
        this.title = title;
        this.author = author;
        this.releaseDate = releaseDate;
    }
    ・・・以下getter/setter
}
package etc9.domain;

public class Author {
    private String firstName;
    private String lastName;

    public Author() {
    }
    public Author(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    ・・・以下getter/setter

BeanKeeperの利用

単純な例では、Store を作成して、save と find を使うだけです。
まずは Store の作成。

Store store = new Store("org.hsqldb.jdbcDriver","jdbc:hsqldb:mem:mymemdb");

上記はインメモリDBの例です。ファイルに永続化するには、

Store store = new Store("org.hsqldb.jdbcDriver","jdbc:hsqldb:testdb");


Bean を準備して save するだけでです。

Author author = new Author("Brian", "Kernighan");
Book book = new Book("The C Programming Language", author, 
                      DateFormat.getDateInstance().parse("1978/1/1"));
store.save(book);
        
List<Book> books = store.find("find book");
for(Book b : books) {
    System.out.println(b.getTitle()+ " : " + b.getAuthor().getFirstName());
}


以下のような出力が得られます。

The C Programming Language : Brian


削除は以下の通り。

store.remove(book);

クエリ言語

ソートを指定するには以下のように order by が使えます。

find book order by title asc
find book order by book.author.firstName


条件指定は以下のように可能です。SQLと同じですね。

find book where title='Java for dummies'
"find book where book.author.firstname='Neal'
find book where book.title like 'Snow%' and (book.author.firstname='Neal' or book.author.lastname<>'Smith')

1対Nのリレーション

ここではListを使用した例を試します。Book は複数の著者と関連するようにします。

public class Book {
    private String title;
    private List<Author> authors;
    private Date releaseDate;

    public Book() {
    }

    public Book(String title, List<Author> authors, Date releaseDate) {
        this.title = title;
        this.authors = authors;
        this.releaseDate = releaseDate;
    }


同様に永続化して

Store store = new Store("org.hsqldb.jdbcDriver","jdbc:hsqldb:mem:mymemdb");

Author author1 = new Author("Brian", "Kernighan");
Author author2 = new Author("Dennis", "Ritchie");

Book book = new Book("The C Programming Language", Arrays.asList(author1, author2), 
        DateFormat.getDateInstance().parse("1978/1/1"));
store.save(book);

List<Book> books = store.find("find book");
for(Book b : books) {
    System.out.println(b.getTitle());
    for(Author a : b.getAuthors()) {
        System.out.println(" -" + a.getFirstName());
    }
}


以下のように著者が2人得られます。ようやくK&Rになれました。

The C Programming Language
 -Brian
 -Dennis


著者名からbookを得たり、

List<Book> books = store.find("find book where book.authors contains author and author.firstname='Brian'");

著者だけを得ることもできます。

List<Author> authors = store.find("find author where firstname like 'B%'");

エンティテイの更新

取得したBeanを変更して store.save() するだけです。

List<Author> authors = store.find("find author where firstname like 'B%'");
for(Author a : authors) {
    a.setLastName("*"+a.getLastName());
    store.save(a);
}

エンティテイのBean自体にプロパティを追加したりした場合も、自動的に処理してくれます。この時永続化したデータはそのままの状態で利用できます。

その他

その他 http://beankeeper.netmind.hu/tutorial.php のチュートリアルを参照してください。
find メソッドとクエリ言語がタイプセーフとならないのが惜しい感じ。