Home日記コラム書評HintsLinks自己紹介
 

Hibernate Tips

Hibernate Tips

Hibernate を使ってみて、 何となく分かってきたちょっとしたノウハウのメモ。

Field 'hoge' doesn't have a default value

原因はこのあたりにあった。

    <subclass name="com.phinloda.orm.KVList" discriminator-value="Li">
        <list name="value" lazy="true" cascade="none">
            <key column="parent" not-null="false" />
            <list-index column="lpos" />
            <many-to-many column="vli" class="memolyst" />
        </list>
    </subclass>

これはちょっとややこしいクラスの継承で発生したエラーである。 Hibernate のサンプルには、 属性を override しているようなクラスの例が出てこない。

結論だけ書く。 次のように直して解決。

    <subclass name="com.phinloda.orm.KVList" discriminator-value="Li">
        <list name="value" lazy="true" cascade="none">
            <key column="parent" not-null="false" />
            <list-index>
                <column name="lpos" not-null="false"/>
            </list-index>
            <many-to-many class="memolyst" />
                <column name="vli" not-null="false"/>
            </many-to-many>
        </list>
    </subclass>

Table per class hierarchy の戦略を使うとき、 コレクションは別テーブルにマッピングされる。 先の例では、 テーブルを特に指定していないから、 value というテーブルが自動的に生成されてしまう。 名前を指定したい場合は、 次のようにして明示的に指定する。

        <list name="value" table="listtable" lazy="true" cascade="none">
        ...

(2006-06-16)

longtext

MySQL を使うときに、 type を text と指定すると、 65535 文字まで使えるようなカラムができる。 longtext を使いたい場合はどう指定するかというと、 mapping の property のところに length を指定すればいい。

    <joined-subclass name="com.phinloda.orm.KVText" table="kvtx"
        extends="memolyst">
        <key column="id" />
        <property name="value" type="text" column="value" length="2147483647" />
    </joined-subclass>

このように length を指定すると、 type を text と指定しても、 MySQL の longtext を使うような SQL を生成してくれる。

create table kvtx (id integer not null, value longtext, primary key (id));

(2006-06-03)

DISTINCT

n+1 問題を解決するために Collection を left join すると、 同じ内容の行が複数 select されてしまう。 これは仕様で、 マニュアルには set にマッピングする方法が紹介されている。

Query mothersWithKittens = (Cat) session.createQuery(
    "select mother from Cat as mother left join fetch mother.kittens");
Set uniqueMothers = new HashSet(mothersWithKittens.list());

Note that queries that make use of eager fetching of collections usually return duplicates of the root objects (but with their collections initialized). You can filter these duplicates simply through a Set.
(10.4.1. Executing queries)

超訳: コレクションをイーガーフェッチで持ってくるようなクエリを使うと、 内容は一発で確かに取得できるのだが、 基本的に、結果に同じ内容の行が含まれてしまう。 重複を除去したいなら、Set を使うのが簡単である。

Note

イーガーフェッチというのは餃子とかではなくて、 確か Hibernate in Action の和訳でそういう言葉になっていたような気がしたので、 そう書いた。

それなら単に distinct を使えばいいのではないか? ところが、次のような HQL を使っても思った結果が得られない。

select distinct hoge from HogeClass as hoge
left join fetch hoge.values;

かなりハマった。 結論。 3.1 だとダメ。 この機能は 3.2.0 alpha1 から使えるようになったので、 それ以降のバージョンにしてみるとよい。

(2006-05-08)

foreign key

MySQL、Oracle で、 foreign key constraint fails というエラーメッセージが出ることがある。

MySQL の場合、

このエラーを回避するために、 最後の手段として、foreign key を生成しないという裏技がある。 これは、 key の属性に foreign-key="none" を指定することで実現できる。

(2006-03-27)