続・双方向で 1 対 1 関連の Lazy フェッチ

この前の続き.
da-yoshi さんが

また、CASCADEに関しては、自然キーを使っている関連については、外部キー制約を持つ方からCASCADEするようにすればうまく動くみたいです。ただ・・・普通制約がある方が「子」のような気がするので、基本的にCASCADEについては制限があると思った方がいいのかも・・・

と書いておられたので,ちょっと試してみました.


この前の例では,Test4 の主キー (id) に Test3 の主キー (id) への外部キー制約を付けていました.
普通,この向きに制約を付けると Test3 が親側で Test4 が子側という感じがしますよね.
まぁ,1 対 1 で,どっちとも 1..1 なんだから親も子もない気もしますけど.
ともあれ (JW),それを逆にして,Test4 を親側に見立てて cascade="all" を付ければうまく動く??
そんなわけで (どんなわけで?),やってみました.
マッピングファイルは Test4 の <one-to-one> を次のように変更.

        <one-to-one name="test3" constrained="true" cascade="all"/>

そしてテストメソッドの冒頭を次のように変更.

        Test3 test3 = new Test3();
        test3.setName("TEST3");

        Test4 test4 = new Test4();
        test4.setName("TEST4");
        test4.setTest3(test3);
        test3.setTest4(test4);

        session.save(test4);
        session.flush();
        session.clear();

Session#save() に渡しているのは test4 だけで,test3 は渡していません.


その結果.

Hibernate: insert into Test3 (version, name, id) values (?, ?, null)
Hibernate: call identity()
Hibernate: insert into Test4 (version, name, id) values (?, ?, ?)
Hibernate: select 
               test3x0_.id as id0_0_, test3x0_.version as version0_0_, test3x0_.name as name0_0_ 
           from 
               Test3 test3x0_ 
           where 
               test3x0_.id=?
TEST3.ID:103
TEST3.NAME:TEST3
TEST3.VERSION:2006-02-02 03:02:11.688

TEST4.ID:103
Hibernate: select 
               test4x0_.id as id1_0_, test4x0_.version as version1_0_, test4x0_.name as name1_0_ 
           from 
               Test4 test4x0_ 
           where 
               test4x0_.id=?
TEST4.NAME:TEST4
TEST4.VERSION:2006-02-02 03:02:11.766

Hibernate: select 
               test4x0_.id as id1_0_, test4x0_.version as version1_0_, test4x0_.name as name1_0_ 
           from 
               Test4 test4x0_ 
           where 
               test4x0_.id=?
TEST4.ID:103
TEST4.NAME:TEST4
TEST4.VERSION:2006-02-02 03:02:11.766

TEST3.ID:103
Hibernate: select 
               test3x0_.id as id0_0_, test3x0_.version as version0_0_, test3x0_.name as name0_0_ 
           from 
               Test3 test3x0_ 
           where 
               test3x0_.id=?
TEST3.NAME:TEST3
TEST3.VERSION:2006-02-02 03:02:11.688

おおぉぉぉ...
キレイに動きますね.ちょっとびっくり.
ちなみに SQL は手で整形してます>某巨大掲示板の 64 さん


どうやら,Session#save() に渡されたオブジェクトに constrained="true"<one-to-one> 関連があると,関連先を先に INSERT しにいっちゃうみたいですね.
この前の場合だと,Test3 を INSERT する前に Test4 を INSERT しようとして,その前に Test3 を INSERT しようとするんだけどもう永続化しつつあるから無視して,でも Test4 を INSERT しにいっても Test3 がまだ INSERT されてないから外部キー制約違反で残念な思いをすることに.
上のようにすると,Test4 をINSERT するまえに Test3 を先に INSERT しようとして,その前に Test4 を INSERT しようとするんだけどもう永続化しつつあるから無視して Test3 が INSERT されて,その後で Test4 が INSERT されておっけー! みたいな.
でもなんか気持ち悪いなぁ.


個人的には cascade="all" なんか外して Dao で頑張ればいいんじゃないかと思ったり.

public class Test3DaoImpl implements Test3Dao {
    public void save(Test3 test3) {
        Session session = sessionFactory.getSession();
        session.save(test3);
        session.save(test3.getTest4());
    }
}

みたいな.