Hibernate 入門寸前

直前と寸前ではどっちが際どいのでしょうか? どっちでもいいですか,そうですよね.とりあえずここでは寸前のほうが際どいということでよろしくお願いします(何を?).
さて,入門直前でHibernateを使う上で必要なものはだいたい分かったので,まずは最初の一歩を踏み出してみたいと思います.おっと,踏み出してしまうと寸前ではなくなるので,最初の一歩を踏み出そうとしてみようと思います.
ということで永続クラスとかテーブルとか作らなきゃいけないわけですが,始から大掛かりなことはしたくないので,既存のテーブルを使う方向で考えてみます.OracleのDUAL表を使うなんていいかなぁ? カラム1個だし主キーはないし.(^^;
なぁんて考えてDualクラスを作ったりしてみたのですが...
主キーがない場合のマッピングファイルの書き方が分かりませんでした.(;_;)
無念だ.
しょうがないので,HSQLDBのDatabase ManagerからInsert test dataすると作られるcustomer表を使ってみることにします.テーブルはもちろんデータまで用意してもらえるのでラクチン.
customerテーブルはこんな感じ.

カラム名主キー
idinteger
firstnamevarchar 
lastnamevarchar 
streetvarchar 
cityvarchar 
ということで,このテーブルに対応する永続クラスを作りましょう.お約束はデフォルトコンストラクタがあることと,JavaBeans流のプロパティがあることだけっぽい.簡単♪
こんな感じ.

package study;

public class Customer {
    private int id;
    private String firstName;
    private String lastName;
    private String street;
    private String city;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getStreet() {
        return street;
    }
    public void setStreet(String street) {
        this.street = street;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String toString() {
        return Integer.toString(id) + " : " + firstName + " " + lastName + ", " + street + " " + city;
    }
}

次にcustomerテーブルとstudy.Customerクラスのマッピングファイル,study/Customer.cfg.xmlを作ります.リファレンスやら「オープンソースJavaプロダクツ (isbn:4774119989)」やら眺めて書いてみるテスト.

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"
>
<hibernate-mapping>
    <class name="study.Customer" table="customer">
        <id name="id">
            <generator class="increment"/>
        </id>

        <property name="firstName"/>
        <property name="lastName"/>
        <property name="street"/>
        <property name="city"/>
    </class>
</hibernate-mapping>

<generator>要素に何を指定すればいいのかよく分かっていないのですが,主キーの生成に使われるとのこと.今回はもうテーブルにデータが入っているので insert する気はないし,一番無害そうなやつを書いてみるテスト.
それから,JDBCの接続情報などを記述した hibernate.cfg.xml を使うと楽っぽいので,これも書いてみるテスト.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration
    PUBLIC "-//Hibernate/Hibernate Configuration DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"
>
<hibernate-configuration>
    <session-factory>
        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="connection.url">jdbc:hsqldb:hsql://localhost:9001</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>
        <property name="dialect">net.sf.hibernate.dialect.HSQLDialect</property>
        <property name="show_sql">true</property>

        <mapping resource="study/Customer.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

使用するマッピングファイルもここで定義しちゃうんですね.
さて,後はHibernateを使うのみ!
やるべきことは,Configurationhibernate.cfg.xml を渡して初期化して,そこから SessionFactory を取ってきて,そこからさらに Session を取ってきて,その問合せメソッドである find(String) を呼べば,永続クラス(この場合はもちろんCustomer)の List が返ってくるらしい.ふむふむ.
Session#find(String) に渡す文字列は,SQLfrom 以降でいいっぽい.
ということで実行用のクラスを作成!

package study;
import java.util.Iterator;
import java.util.List;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.cfg.Configuration;

public class Main {
    public static void main(String[] args) {
        try {
            Configuration config = new Configuration();
            SessionFactory factory = config.configure().buildSessionFactory();
            Session session = factory.openSession();
            List customers = session.find("from customer");
            Iterator it = customers.iterator();
            while (it.hasNext()) {
                System.out.println(it.next());
            }
        }
        catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

そして実行!!

 Hibernate: select  from
 - SQL Error: -11, SQLState: 37000
 - Unexpected token: FROM in statement [select  from]
 - SQL Error: -11, SQLState: 37000
 - Unexpected token: FROM in statement [select  from]
 - Could not execute query
 java.sql.SQLException: Unexpected token: FROM in statement [select  from]
 ・
 ・
 ・

ぐはぁっ,なぜに? なぜにSQLselect from だけなの?
うーみゅ,まさか入門寸前でいきなり躓くとは... 無念だ.
こういう場合はどこを調べればいいんだろう?
...
リファレンスの「第9章 Hibernate Query Language」に気になること発見.

クエリは、Javaクラスやプロパティ名を除いて、大文字・小文字の区別はありません。

なんですと? クエリにJavaクラス? えぇっ? もしかして,from の後ろはテーブル名じゃなくてJavaのクラス名なの? うひゃー.
ってことは Session#find(String) の引数は "from customer" ではなくて "from Customer" にしなきゃいけないってこと? あれ,"from study.Customer" か?
両方やってみました.どちらでもよかったっぽい.いずれにしても

 Hibernate: select customer0_.id as id, customer0_.firstName as firstName, customer0_.lastName as lastName, customer0_.street as street, customer0_.city as city from customer customer0_
 0 : Laura Steel, 429 Seventh Av. Dallas
 1 : Susanne King, 366 - 20th Ave. Olten
 2 : Anne Miller, 20 Upland Pl. Lyon
・
・
・

という具合に全件取得することが出来ました.
そうか,Hibernateの問合せ言語がSQLじゃなくてHQLとなっているのはそういうことなのか... 油断したなぁ.心より恥じる.


ともあれ(JW),無事にHibernateはじめの一歩を体験することが出来ました.もとい,その寸前まで体験出来ました.よかった.ここでクリアできなかったら,寸前より際どい言葉を捜さなきゃいけないところだったよ.せーふ.
ということで,次回から本格的に入門していきたいと思うのですが,いまだに進め方がイメージできていません.Springの時はリファレンスの通りに学習したのですが,あれはSpringが単純なコンテナの上位にいろいろな機能が乗っかっていたからできたことで,Hibernateでもそれができるのでしょうか? 今回みたいに簡単なことをするのでさえ9章まで見に行ったわけで... 困ったにゃぁ.
いいや,明日考えよう.