JPA / EJBコードで「デタッチされたエンティティが永続エラーに渡されました」


81

この基本的なJPA / EJBコードを実行しようとしています。

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setId(1);
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }

このエラーが発生します:

javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.JPA.Database

何か案は?

私はインターネットで検索しました、そして私が見つけた理由は:

これは、オブジェクトの作成方法、つまりIDプロパティを明示的に設定した場合に発生しました。ID割り当てを削除すると修正されました。

しかし、私はそれを取得できませんでした、コードを機能させるために何を変更する必要がありますか?

回答:


50

ERD

2つのエンティティAlbumとが存在するとしPhotoます。アルバムにはたくさんの写真が含まれているので、1対多の関係です。

アルバムクラス

@Entity
public class Album {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Integer albumId;

    String albumName;

    @OneToMany(targetEntity=Photo.class,mappedBy="album",cascade={CascadeType.ALL},orphanRemoval=true)
    Set<Photo> photos = new HashSet<Photo>();
}

フォトクラス

@Entity
public class Photo{
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Integer photo_id;

    String photoName;

    @ManyToOne(targetEntity=Album.class)
    @JoinColumn(name="album_id")
    Album album;

}

永続化またはマージする前に行う必要があるのは、各写真にアルバム参照を設定することです。

        Album myAlbum = new Album();
        Photo photo1 = new Photo();
        Photo photo2 = new Photo();

        photo1.setAlbum(myAlbum);
        photo2.setAlbum(myAlbum);       

これは、永続化またはマージする前に、関連するエンティティをアタッチする方法です。


2
ジェネリックスを使用する場合は、「targetEntity = Photo.class」を使用する必要はありません
Rollerball

こんにちは、アルバムオブジェクトをphoto1とphoto2に設定した後...写真またはアルバムのリストを保存する必要があるオブジェクトは何ですか?
Dilanka Rathnayake 2017年

129

オブジェクトのIDが設定されているため、エラーが発生します。Hibernateは、一時オブジェクトと分離オブジェクトを区別し、一時オブジェクトでpersistのみ機能します。persistオブジェクトがデタッチされていると結論付けた場合(IDが設定されているため)、「デタッチされたオブジェクトは永続化に渡されました」というエラーが返されます。詳細については、こちらこちらをご覧ください

ただし、これは自動生成される主キーを指定した場合にのみ適用されます。フィールドが常に手動で設定されるように構成されている場合、コードは機能します。


私が言うとき、私は技術的に正しいのでしょうか?私は休止状態ではなくJPAを使用しているので、上記のステートメントは正しく適用されるべきではありませんか?私はJPAの初心者です(正確には3つのays:P)
zengr 2010年

SunのJPAJavadocjava.sun.com/javaee/5/docs/api/javax/persistence/…)とToplinkのJPA Javadocはまったく同じであり、技術的に正しいことを示唆しています。しかし、それは実際には、persist()がどのように動作するべきかという仕様に要約されており、悲しいことに、それが何であるかはわかりません。
Tomislav Nakic-Alfirevic 2010年

この解決策は私のために働いた。IDをどこかに保存したまま、オブジェクトを永続化していた。次に、その既存のオブジェクトを新しい値で上書きしたいので、オブジェクトを作成し、IDをコピーして戻しましたが、保存しようとすると爆発しました。最終的に、DB(findById)を再クエリし、変更を加えてから、そのオブジェクトを永続化する必要がありまし
cs94njw 2012年

24

削除する

user.setId(1);

DB上で自動生成されるため、persistコマンドを続行します。


12

私は答えを得ました、私は使っていました:

em.persist(user);

永続化の代わりにマージを使用しました:

em.merge(user);

しかし、わからない、なぜ持続が機能しなかったのか。:(


11
これは解決策ではありません!
Ammar Bozorgvar 2011

1
私は知っていますが、これは私にとってはうまくいきました。あなたのために働いた他の答えはここにありますか?はいの場合、私はそれを選択することを嬉しく思います。
zengr 2011

4
オブジェクトが休止状態のセッションから切り離されたか、オブジェクトが一時的であるために機能しましたが、主キーが宣言されているため、休止状態では切り離されたと見なされます。マージを使用してオブジェクトをセッションに再度アタッチすると、データベース内のオブジェクトを更新できます。 ; 参照:docs.jboss.org/hibernate/core/3.3/reference/en/html/…
ベン・

9

を生成するために使用する場合 id = GenerationType.AUTOエンティティで戦略。

に置き換えuser.setId (1)られuser.setId (null)、問題は解決されます。


5

私はその種類が遅すぎることを知っています、そして確かに誰もが答えを得ました。ただし、これにもう少し追加する必要があります。GenerateTypeが設定されている場合、オブジェクトのpersist()はIDを生成することが期待されます。

ユーザーによってIDに設定された値がすでにある場合、hibernateはそれを保存済みレコードとして処理するため、デタッチされたものとして扱われます。

IDがnullの場合-この状況では、IDがテーブルまたはシーケンスなどから生成されない限り、タイプがAUTOまたはIDENTITYなどの場合にnullポインタ例外が発生します。

設計:これは、テーブルに主キーとしてBeanプロパティがある場合に発生します。GenerateTypeは、IDが自動生成される場合にのみ設定する必要があります。これを削除すると、挿入はユーザー指定のIDで機能するはずです。(プロパティを主キーフィールドにマップするのは悪い設計です)


5

ここで、.persist()レコードのみを挿入します。.merge()を使用すると、現在のIDのレコードが存在するかどうかがチェックされ、存在する場合は更新されます。存在しない場合は、新しいレコードが挿入されます。


私があなたの答えを得るまで、それは私にたくさんの時間を要しました。どうもありがとうございました!
Thach Van

3

データベースのidを主キーと自動インクリメントに設定した場合、次のコード行は間違っています。

user.setId(1);

これで試してください:

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }

私はそれを試しましたが、このエラーが発生することがわかっています:detached entity passed to persist
s1ddok 2016年

2

私はこの問題を抱えていました、そしてそれは第2レベルのキャッシュによって引き起こされました:

  1. Hibernateを使用してエンティティを永続化しました
  2. 次に、2番目のレベルのキャッシュと相互作用しなかった別のプロセスから作成された行を削除しました
  3. 同じ識別子を持つ別のエンティティを永続化しました(私の識別子の値は自動生成されません)

したがって、キャッシュは無効化されていないため、hibernateは同じエンティティのデタッチされたインスタンスを処理していると想定しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.