EclipseLinkでDBに存在しないレコードに対しての一意制約例外が発生する
この記事は最終更新日から8年以上が経過しています。
TL;DR
@Id が付いているパラメタにDB上で auto_increment が設定されている場合、
そのパラメタにコード上で値を入れて persist() すると一意制約例外が発生する。
回避するためには persist() の代わりに merge() を使う。
解説
発生状況
persistence.xml に以下が設定されている
<property name="eclipselink.validate-existence" value="true"/>
コード上で @Entity のオブジェクトを new した後、全てのパラメタに値を詰めて persist() したところ
javax.persistence.EntityExistsException: Exception Description: Cannot persist detached object
が発生した。
DB上では、該当オブジェクトの @Id が付いているパラメタに auto_increment が設定されていた。
原因
http://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/p_validate_existence.htm
を見ると persistence context に存在しない場合にエラーが発生すると書いてあることから調査を開始してみた。
JPAで処理される際に、 auto_increment のカラムに @Id が付与されている場合
GeneratedValue strategy=GenerationType.SEQUENCE
と判断される
(@Id指定だけの時はDBみて自動判断? http://otndnld.oracle.co.jp/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#Id )
オブジェクトを persist() した際に
GeneratedValue strategy=GenerationType.SEQUENCE
なのに @Id のパラメタに値が入っている
かつ PersistenceContext に入ってない → 分離状態(detached object)と判定
detached object なのに persist しようとしている
→ javax.persistence.EntityExistsException: Exception Description: Cannot persist detached object
という流れでエラーになっている
対処方法
- @Id 指定されているパラメタに値が入っている場合は、persist() の代わりに merge() を使う
- 参考 → http://stackoverflow.com/questions/10463460/cannot-persist-detached-object
参考
- http://kokuzawa.github.io/blog/2014/01/31/entityexistsexception/
- http://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/p_validate_existence.htm
- http://stackoverflow.com/questions/10463460/cannot-persist-detached-object
- http://otndnld.oracle.co.jp/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#Id
- http://otndnld.oracle.co.jp/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#GeneratedValue
- http://etc9.hatenablog.com/entry/20090830/1251606823