Hibernateコレクションマッピング規則


本文は主にHibernate高級集合マッピング(Advanced collection mappings)を紹介し、Hibernate高級集合マッピングは主に秩序集合、双方向関連、双方向関連に分けられ、秩序集合クラス、三重関連(Ternary associations)、使用に関連する.1.秩序集合(Sorted collections)
Hibernateプレミアムコレクションマッピングはjavaの実装をサポートする.util.SortedMapとjava.util.SortedSetの集合.マッピングファイルでコンパレータを指定する必要があります.

  
  
  
  
  1. <set name="aliases"   
  2.             table="person_aliases"   
  3.             sort="natural"> 
  4.     <key column="person"/> 
  5.     <element column="name" type="string"/> 
  6. </set> 
  7.  
  8. <map name="holidays" sort="my.custom.HolidayComparator"> 
  9.     <key column="year_id"/> 
  10.     <map-key column="hol_name" type="string"/> 
  11.     <element column="hol_date" type="date"/> 
  12. </map> 

sort属性で許容する値にはunsorted,natural,および実装javaが含まれる.util.Comparatorのクラスの名前.
分類集合の行為は実際にjavaに似ている.util.TreeSetまたはjava.util.TreeMap.
データベースがコレクション要素を独自にソートする場合は、set、bag、mapマッピングのorder-byプロパティを使用します.この解決策はjdk 1に限られる.4以上のjdkバージョンでのみ実現できます(LinkedHashSetまたはLinkedHashMapによって実現されます).メモリではなくSQLクエリーでソートを完了します.

  
  
  
  
  1. <set name="aliases" table="person_aliases" order-by="lower(name) asc"> 
  2.     <key column="person"/> 
  3.     <element column="name" type="string"/> 
  4. </set> 
  5.  
  6. <map name="holidays" order-by="hol_date, hol_name"> 
  7.     <key column="year_id"/> 
  8.     <map-key column="hol_name" type="string"/> 
  9.     <element column="hol_date" type="date"/> 
  10. </map> 

注意:このorder-byプロパティの値は、HQLではなくSQLソート句です.
関連付けは、実行時に集合filter()を使用して任意の条件に従ってソートすることもできます.

  
  
  
  
  1. ssortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list(); 

2.双方向関連(Bidirectional associations)
双方向の関連付けでは、関連付けられたいずれかの端から別の端にアクセスできます.Hibernateでは、2つのタイプの双方向の関連付けがサポートされています.
◆一対多(one-to-many)Setまたはbag値は一端、個別値(非集合)は他端
◆マルチペアマルチ(many-to-many)両端がsetまたはbag値
双方向のマルチペアマルチ関連付けを確立するには、2つのmany-to-manyを同じデータベース・テーブルに関連付けてマッピングし、その一端をinverseとして定義します(どの一端を使用するかは選択に従いますが、インデックス・セットではありません).
ここにはmany-to-manyの双方向関連の例がある.各categoryには多くのitemsがあり、各itemsは多くのcategoriesに属することができます.

  
  
  
  
  1. <class name="Category"> 
  2.     <id name="id" column="CATEGORY_ID"/> 
  3.     ...  
  4.     <bag name="items" table="CATEGORY_ITEM"> 
  5.         <key column="CATEGORY_ID"/> 
  6.         <many-to-many class="Item" column="ITEM_ID"/> 
  7.     </bag> 
  8. </class> 
  9.  
  10. <class name="Item"> 
  11.     <id name="id" column="CATEGORY_ID"/> 
  12.     ...  
  13.  
  14.     <!-- inverse end --> 
  15.     <bag name="categories" table="CATEGORY_ITEM" inverse="true"> 
  16.         <key column="ITEM_ID"/> 
  17.         <many-to-many class="Category" column="CATEGORY_ID"/> 
  18.     </bag> 
  19. </class> 

関連する逆エンドのみを変更した場合、この変更は永続化されません.これは、Hibernateが、AからBに接続され、BからAに接続された双方向の関連付けごとにメモリに2回の表現があることを示しています.Javaオブジェクトモデルを思い出すと、Javaで多対多関係を作成する方法がわかりやすくなります.

  
  
  
  
  1. category.getItems().add(item);          // The category now "knows" about the relationship  
  2. item.getCategories().add(category);     // The item now "knows" about the relationship  
  3.  
  4. session.persist(item);                   // The relationship won''t be saved!  
  5. session.persist(category);               // The relationship will be saved 

非反転端子は、メモリの表示をデータベースに保存するために使用されます.
1対の複数の双方向関連付けを作成するには、1対の複数の関連付けを1対の複数の関連付けとして同じテーブルのフィールドにマッピングし、「複数」の一端にinverse=「true」を定義します.

  
  
  
  
  1. <class name="Parent"> 
  2.     <id name="id" column="parent_id"/> 
  3.     ....  
  4.     <set name="children" inverse="true"> 
  5.         <key column="parent_id"/> 
  6.         <one-to-many class="Child"/> 
  7.     </set> 
  8. </class> 
  9.  
  10. <class name="Child"> 
  11.     <id name="id" column="child_id"/> 
  12.     ....  
  13.     <many-to-one name="parent"   
  14.         class="Parent"   
  15.         column="parent_id" 
  16.         not-null="true"/> 
  17. </class> 

「一」の端でinverse=「true」を定義してもカスケード操作には影響しません.両者は直交する概念です.
3.双方向関連、秩序化集合クラスに関する
一端がまたはである双方向関連については,特に考慮する必要がある.サブクラスのプロパティがインデックスフィールドにマッピングされている場合、問題なく、inverse=「true」をコレクションクラスマッピングで使用できます.

  
  
  
  
  1. <class name="Parent"> 
  2.     <id name="id" column="parent_id"/> 
  3.     ....  
  4.     <map name="children" inverse="true"> 
  5.         <key column="parent_id"/> 
  6.         <map-key column="name"   
  7.             type="string"/> 
  8.         <one-to-many class="Child"/> 
  9.     </map> 
  10. </class> 
  11.  
  12. <class name="Child"> 
  13.     <id name="id" column="child_id"/> 
  14.     ....  
  15.     <property name="name"   
  16.         not-null="true"/> 
  17.     <many-to-one name="parent"   
  18.         class="Parent"   
  19.         column="parent_id" 
  20.         not-null="true"/> 
  21. </class> 

ただし、サブクラスにこのような属性が存在しない場合、この関連付けは真の双方向関連付け(情報が非対称であり、関連付けの一端には他の一端にない情報がある)とは考えられません.この場合、inverse=「true」は使用できません.このように使用する必要があります.

  
  
  
  
  1. <class name="Parent"> 
  2.     <id name="id" column="parent_id"/> 
  3.     ....  
  4.     <map name="children"> 
  5.         <key column="parent_id" 
  6.             not-null="true"/> 
  7.         <map-key column="name"   
  8.             type="string"/> 
  9.         <one-to-many class="Child"/> 
  10.     </map> 
  11. </class> 
  12.  
  13. <class name="Child"> 
  14.     <id name="id" column="child_id"/> 
  15.     ....  
  16.     <many-to-one name="parent"   
  17.         class="Parent"   
  18.         column="parent_id" 
  19.         insert="false" 
  20.         update="false" 
  21.         not-null="true"/> 
  22. </class> 

なお、このマッピングでは、関連する集合クラスの「値」の一端が外部キーの更新を担当する.TODO: Does this really result in some unnecessary update statements?
4.三重関連(Ternary associations)
3重相関をマッピングするには、3つの可能な方法があります.1つ目は、Mapを使用して、関連付けをインデックスとして使用します.

  
  
  
  
  1. <map name="contracts"> 
  2.     <key column="employer_id" not-null="true"/> 
  3.     <map-key-many-to-many column="employee_id" class="Employee"/> 
  4.     <one-to-many class="Contract"/> 
  5. </map> 
  6. <map name="connections"> 
  7.     <key column="incoming_node_id"/> 
  8.     <map-key-many-to-many column="outgoing_node_id" class="Node"/> 
  9.     <many-to-many column="connection_id" class="Connection"/> 
  10. </map> 

2つ目の方法は、単純に関連をエンティティクラスに再モデリングすることです.これは私たちが最もよく使う方法です.
最後の選択肢は複合要素を使用することです.後で説明します.
5.の使用
「コンビネーション・プライマリ・キー(composite keys)は悪いものだ」と「エンティティは(無機的に)自分で生成した代用識別子(surrogate keys)を使用すべきだ」と完全に信じている場合はの観点から、いくつかの奇妙な感じがするかもしれませんが、私たちがこれまで示した多対多の関連と値の集合は、連合プライマリ・キーを持つテーブルにマッピングされています.今、この点は議論に値する.単純な関連テーブルでは、代用識別子から何の利益も得られないように見えます(組合せ値の集合を使用すると少しの利益が得られるかもしれませんが).しかし、Hibernateは、複数の関連と値の集合に対して代用識別子を使用するテーブルを得るための機能を提供しています.
プロパティを使用すると、bagの意味を使用してリスト(またはCollection)をマッピングできます.

  
  
  
  
  1. <idbag name="lovers" table="LOVERS"> 
  2.     <collection-id column="ID" type="long"> 
  3.         <generator class="sequence"/> 
  4.     </collection-id> 
  5.     <key column="PERSON1"/> 
  6.     <many-to-many column="PERSON2" class="Person" fetch="join"/> 
  7. </idbag> 

人工のidジェネレータは、まるで実体クラスのようです!集合の各行には異なる人工キーワードがあります.しかし、Hibernateは特定の行の人工キーワードを取得するメカニズムを提供していません.
注意の更新性能は普通のよりずっと高いです!Hibernateは、list、map、setを処理するのと同じように、異なるローに効率的に位置決めし、それぞれ更新または削除を行うことができます.現在の実装では、identity識別子ジェネレータポリシーを使用してセットの識別子を生成することはサポートされていない.