web-dev-qa-db-ja.com

JPA / EJBコードで「エラーを持続させるために渡された分離されたエンティティ」

この基本的な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割り当てを削除すると修正されました。

しかし、私はそれを手に入れませんでした。コードを機能させるために何を修正する必要がありますか?

78
zengr

ERD

2つのエンティティAlbumPhotoがあるとします。アルバムには多くの写真が含まれているため、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);       

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

50
zawhtut

このエラーは、オブジェクトのIDが設定されているために発生します。 Hibernateは一時オブジェクトと分離オブジェクトを区別し、persistは一時オブジェクトでのみ動作します。 persistがオブジェクトが切り離されたと判断した場合(IDが設定されているため)、「永続化するために渡された切り離されたオブジェクト」エラーを返します。詳細は here および here をご覧ください。

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

削除する

user.setId(1);

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

22
Ammar Bozorgvar

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

em.persist(user);

Persistの代わりにmergeを使用しました。

em.merge(user);

しかし、どうして永続化が機能しなかったのかわかりません。 :(

12
zengr

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

user.setId (1)user.setId (null)に置き換え、問題が解決しました。

9

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

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

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

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

5
haripriya

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

5
PSR

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

user.setId(1);

これで試してください:

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

この問題が発生したのは、2次キャッシュが原因でした。

  1. 休止状態を使用してエンティティを永続化しました
  2. 次に、セカンドレベルキャッシュと対話しない別のプロセスから作成された行を削除しました
  3. 同じ識別子で別のエンティティを永続化しました(識別子の値は自動生成されません)

したがって、キャッシュは無効化されていないため、休止状態は同じエンティティの切り離されたインスタンスを処理していると想定していました。

2
hertzsprung

エンティティオブジェクトがSerializableインターフェイスを実装していないというエラーの別の理由

@Entity
@Table(name = OddInstance.objectName, uniqueConstraints = @UniqueConstraint(columnNames = {"alias"}))
@NamedQueries({
    @NamedQuery(name=OddInstance.findByAlias,
            query="from OddInstance where alias = :alias"),
    @NamedQuery(name=OddInstance.findAll,
            query="from OddInstance")
})
public class OddInstance implements Serializable {
    // ...
}
0
Evgeny Lebedev