hibernate 同一テーブルの多対多構造
さて、mixiマイミクのような、
同一テーブルの多対多構造を持つ場合、
hibernateを使うと何かと問題が出やすい。
特に、insert、delete。
これがスタンダードなやり方かわからないが、
一応うまくいっているので、紹介する。
まず、DBの構造。
ユーザは割愛するとして、
リンクテーブルは
parent_user_id
friend_usr_id
の2つがprimary keyになっているとしましょう。
そんでもって、
many-to-oneで定義済みってことで。
まず、追加。
ユーザAとBをマイミクにする場合、
A.getFriends()でマイミクさんを取れることにしましょう。
その場合、
単純に
A.getFriends().add(B);
B.getFriends().add(A);
とすれば良いような気がしますが、
これが失敗します。
入れ子構造になっているため、2行目でBが追加されたAが入るため、
insert文が2つ流れてしまい、重複キーエラーが出るんですね。
これを解消するためには、
session.evict(B);
A.getFriends().add(B);
B = session.load(); <=読み直し
session.evict(A);
B.getFriends().add(A);
とevict()を駆使する必要があります。
同様に、削除も
A.getFriends().remove(B);
B.getFriends().remove(A);
ではダメで、
session.evict(B);
A.getFriends().remove(B);
B = session.load(); <=読み直し
session.evict(A);
B.getFriends().remove(A);
とする必要があります。
実際のところ、この設計がまずいのかもしれませんがね。