daybreaksnow's diary

私を私と呼びたい

[Hibernate]パラダイムミスマッチ・関連の問題

Javaのクラス図
f:id:daybreaksnow:20130118222956p:plain

DBのER図
f:id:daybreaksnow:20130118222959p:plain

商品は複数のカテゴリに属し、カテゴリには複数の商品が存在する。
これは多対多関連となる。

これをRDB上で実現するためには、商品とカテゴリのマッピングをする中間テーブルを使うことになる。


Java上で中間テーブルクラスを作らずに、この関連を永続化するためには、以下の設定を行う。

・自動生成された時点のhbm(修正前)

<set name="itemCategoryMappings" table="item_category_mapping" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="category_id" not-null="true" />
            </key>
            <one-to-many class="manytomany.ItemCategoryMapping" />
</set>

・修正後hbm

<set name="items" table="item_category_mapping" inverse="false" lazy="true" fetch="select" cascade="all-delete-orphan">
            <key>
                <column name="category_id" not-null="true" />
            </key>
            <many-to-many column="item_id" class="manytomany.Item" />
</set>

変更点は以下の二つ。
・one-to-manyでマッピングファイルとつながっている箇所を、many-to-manyとし、つなげたいクラスに変更する。
・デフォルトではItem、Categoryのどちらもinverse=trueとなっており、この状態では中間テーブルが保存されない。どちらかをinverse=falseにする。今回はカテゴリが妥当だろう。

なお、中間テーブルに関するhbmは必要ない。
また、この場合、中間テーブルのPKはitem_id,category_idとなる。

問題点

・item→マッピングのcascadeをallにしてしまうと、itemの削除時に、マッピングだけでなく、マッピングの先のcategoryと、categoryに紐づくすべてのitemも削除されてしまう。
・itemsへのcascadeがallだと、itemsからremoveしたとき、マッピングファイルのみ削除され、itemは削除されない。
all-delete-orphanにすると、マッピングもitemも削除される。

many-to-many関連は使わないほうがよいのか?


2013/1/28追記
もし独自のPK(mapping_idのような)を持たせる場合は、idbagを利用すればよい。
この場合、item_category_mappingのhbmも作成する必要がある。