2012-12-12 23 views
8

私は2つのエンティティ:AccountAccountRoleを持っています。分離されたオブジェクトをJPAに引き渡す方法はありますか? (分離されたエンティティが継承に渡されます)

public class Account { 
    private AccountRole accountRole; 

    @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER) 
    public AccountRole getAccountRole() { 
     return accountRole; 
    } 

public class AccountRole { 
    private Collection<Account> accounts = new ArrayList<Account>(); 

    @OneToMany(mappedBy = "accountRole", fetch = FetchType.EAGER) 
    public Collection<Account> getAccounts() { 
     return accounts; 
    } 

私は、データベースからaccountRoleを取り、私のAccountを持続しようとすると、問題が来ます。 この時点で私は自分のアカウントを作成しましたが、ロールはすでにdbに存在しています。

AccountRole role = accountService.getRoleFromDatabase(AccountRoles.ROLE_USER); 
account.setAccountRole(role); 

//setting both ways, as suggested 
public void setAccountRole(AccountRole accountRole) { 
    accountRole.addAccount(this); 
    this.accountRole = accountRole; 
} 

entityManager.persist(account); // finally in my DAO 

私はこの読み:JPA/Hibernate: detached entity passed to persistそして、私は理解し、私は私のセッターでやっているものをするように、私は、両方の方向からのエンティティの値を設定する必要があります。

まだエラーが発生しています。

org.hibernate.PersistentObjectException: detached entity passed to persist: foo.bar.pojo.AccountRole 

答えて

16

だけで

entityManager.persist(account); 

を置き換える:

entityManager.merge(account); 

とカスケードマージ許可:

:マージがこれを行いますので

@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.EAGER) 
public AccountRole getAccountRole() { 
    return accountRole; 
} 

を0

あなたのエンティティが新しい場合は、persist()と同じです。 エンティティが既に存在する場合は、そのエンティティが更新されます。

+0

また、 'persist()'はあなたがマネージエンティティを渡したオブジェクトを作成しますが、mergeは渡されたオブジェクトのマネージドコピーを返します。したがって、マージ後にマネージドエンティティが必要な場合は、 'account = entityManager.merge(account)'を実行する必要があります。また、[こちら]を見てください(http://stackoverflow.com/a/1070629/1260908) – rumman0786

3

あなたは、処理中のトランザクションを残すように見えますので、accountRoleは外れます、またはそれは既に他の理由のために分離されます。

entityManager.persist(account)を呼び出す前にentityManager.merge(accountRole)に電話すると修正されるはずです。

EDIT:残念ながら、accountRoleが既にDBに存在するかどうかわからない場合は、クエリで確認する必要があります。それが存在する場合、マージ(存在しない場合)します。それは本当に面倒ですが、私はまだより良い回避策を見ていません。

EDIT2:あなたは残りますmergeメソッドに渡すエンティティ切り離さ - 管理エンティティは、あなたが最初にマージする必要がありますので、その後、mergeの戻り値にaccount上に基準を設定し、mergeによって返されます。

+0

ほとんどの場合、 'AccountRole'はデータベースに存在しません。したがって、' em.persist'を実行するとアカウントとaccountroleが持続され、すべて動作します。今度は自分のコードで自分自身を見つけると、 'AccountRole'をデータベースに2回追加していきます。最初にマージ、成功、そして永続で、重複キー値違反エラー、任意の提案?問題は、時には役割が存在しないことです。 – Jaanus

+0

「ロール」が存在しない場合、全体を「維持」することができますが、ロールが存在する場合、最初に「マージ」しますが、あまりにも面倒なようですね。 – Jaanus

+0

@Jaanus - ああ、あなたは正しいです:)私はそれに応じて答えを編集しました。 – kostja

関連する問題