daybreaksnow's diary

私を私と呼びたい

[Hibernate]1対1関連のマッピング

ユーザとその住所のように、実際は1対1の関連にある場合でも、ER図上では多対1関連で表現することとなる。
この状態でHibernateリバースエンジニアリングをかけると、ユーザから住所はmany-to-one、住所からユーザはone-to-manyの関連でhbmが生成される。

この時、住所からユーザを取得するのにコレクションの操作をするのは面倒である。
このような場合には、one-to-one関連が利用できる。


User.hbm

<many-to-one name="home_address_id" class="hoge.Address" cascade="all" >
      <column name="home_address_id"  unique="true" />
</many-to-one>


Address.hbm
・修正前

 <set name="users" table="user" inverse="true" >
       <key>
           <column name="home_address_id" />
       </key>
       <one-to-many class="hoge.User" />
 </set>

・修正後

<one-to-one name="user" class="hoge.User" property-ref="homeAddress" />

上記のように、one-to-oneタグを利用し、property-refでどのフィールドで紐付くかを指定することで、一対一の関係を表現できる。

また、User.hbmでhome_address_idのunique属性をtrueとしているが、これはリバースエンジニアリング時にのみ影響するものであり、エンティティの保存時はユニークかどうかのチェックは行われない。

そのためDB上でhome_address_idにunique制約が存在しなければ、one-to-one関連を指定している場合であっても、同一のAddressエンティティを複数のユーザに割り当てることが可能となる。

この場合、保存は成功するが、Addressの読み込み時に紐付くUserが特定できないため、下記の例外が発生する。

Exception in thread "main" org.hibernate.HibernateException: More than one row with the given identifier was found: 1, for class: hoge.UserOnetoone