6.1. コレクションの永続化

6.1. コレクションの永続化

コレクション型のフィールドを永続化するには、そのコレクション型がインターフェース型である必要があります。例えば、

public class Product {
    private String serialNumber;
    private Set parts = new HashSet();
    
    public Set getParts() { return parts; }
    void setParts(Set parts) { this.parts = parts; }
    public String getSerialNumber() { return serialNumber; }
    void setSerialNumber(String sn) { serialNumber = sn; }
}

実在するインターフェースには java.util.Setjava.util.Collectionjava.util.Listjava.util.Mapjava.util.SortedSetjava.util.SortedMap などがあります。または、任意のインターフェースが使えます。 (ただし、「任意のインターフェース」を使用する場合は、 org.hibernate.usertype.UserCollectionType の実装クラスを作成する必要があります。)

HashSet のインスタンスを持つインスタンス変数がどのように初期化されるかに注目してみましょう。これは新たに生成された(永続化されていない)コレクション型のプロパティを初期化する最適な方法です。 (例えば persist() により)インスタンスを永続化しようとしたとき、 Hibernate は HashSet を Hibernate 独自の Set の実装クラスに置き換えます。このため、次のようなエラーには注意が必要です。

Cat cat = new DomesticCat();
Cat kitten = new DomesticCat();
....
Set kittens = new HashSet();
kittens.add(kitten);
cat.setKittens(kittens);
session.persist(cat);
kittens = cat.getKittens(); // Okay, kittens collection is a Set
(HashSet) cat.getKittens(); // Error!

Hibernate により注入された永続性コレクションは、インターフェース型に応じて、 HashMapHashSetTreeMapTreeSetArrayList のように振舞います。

コレクションインスタンスは、値型として普通に振舞います。永続化オブジェクトに参照されたときに自動的に永続化され、参照がなくなったときに自動的に削除されます。もしある永続化オブジェクトから別の永続化オブジェクトに渡されたら、その要素は現在のテーブルから別のテーブルに移動するかもしれません。2つのエンティティが同じコレクションインスタンスを共有してはいけません。リレーショナルモデルをベースにしているため、コレクション型のプロパティに null 値を代入しても意味がありません。つまり Hibernate は参照先のないコレクションと空のコレクションを区別しません。

しかしそれほど心配しなくても構いません。普段使っている Java のコレクションと同じように、永続化コレクションを使ってください。双方向関連の意味を理解すればよいのです(これは後ほど説明します)。