12

SpringDataJPAと組み合わせてJPAのオブジェクト@Idとしてプリミティブ型を使用する際の問題を発見しました。親側のCascade.ALLと親子関係があり、子はPKを持ち、同時に親のFKでもあります。

class Parent {
    @Id
    private long id;

    @OneToOne(mappedBy = "parent", cascade = ALL)
    private Child child;
}

class Child {
    @Id
    @OneToOne
    private Parent parent;
}

だから、私が実行すると:

...
Parent parent = new Parent();
Child child  = new Child(parent);
parent.setChild(child);  
em.persist(parent)
...

すべてが正常に動作します。ただし、Spring Data JPAを使用してエンティティを永続化したため、代わりに次のコマンドを実行します。

parentRepository.save(parent); // instead of em.persist(parent);

これは、次の例外を除いて失敗しました。

Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Parent

問題は、Spring Data JPA save()メソッドがエンティティが新しいかどうかをチェックし、新しい場合はem.persist()が使用され、そうでない場合はem.merge()が使用されることでした。

ここで興味深いのは、Springがエンティティが新しいかどうかをチェックする方法です。

getId(entity) == null;

そしてもちろん、これは誤りでした。@ Idの型としてlongを使用し、longのデフォルト値は0でした。longをLongに変更すると、すべてがSpringDataJPAでも機能します。

したがって、プリミティブ型ではなく、プリミティブ型(longではなくLongなど)のオブジェクトラッパーを常に使用することをお勧めします。これを推奨される方法として説明しているサードパーティのリソースは非常に便利です。

4

2 に答える 2

15

はい、あなたが見ているケースのために、プリミティブの代わりにオブジェクトタイプを使用することをお勧めします。エンティティが新規であるか、プリミティブ識別子で既存であるかを区別する方法はありません。私は何年も休止状態を使用しており、識別子には常にオブジェクトを使用しています。

于 2012-07-01T16:59:14.973 に答える
0

オブジェクトタイプを使用します。xmlマッピングでは、「unsaved-value」属性を設定できますが、このための注釈への直接の変換はないと思います。結果として、オブジェクトタイプに固執する方が安全です。

そして、ほとんどのプログラマーは、識別子の「null」値がとにかく保存されていないことを意味することを期待します。

于 2012-07-01T21:43:15.530 に答える