Is there a way to pass a single object to JPA? (deleted object transferred for storage)

I have 2 objects: Account and AccountRole .

 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; } 

The problem occurs when I take an account from the database and try to save my Account . At this point, I just created my account and the role already exists in 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 

I read this: JPA / Hibernate: the remote object was handed over for storage. And as I understand it, I have to set the values โ€‹โ€‹of entities from both directions, so what I do in my setter.

The error still appears.

  org.hibernate.PersistentObjectException: detached entity passed to persist: foo.bar.pojo.AccountRole 
+9
java hibernate jpa entitymanager
source share
3 answers

Just replace

 entityManager.persist(account); 

from:

 entityManager.merge(account); 

And allow cascading merge:

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

Since merge does this:

If your entity is new, it is the same as persist (). But if your object already exists, it will update it.

+16
source share

It looks like you will leave the transaction during processing, so accountRole will accountRole off or already disconnected for other reasons.

A call to entityManager.merge(accountRole) before calling entityManager.persist(account) should fix it.

EDIT: Unfortunately, if you cannot be sure that accountRole already exists in the database, you will need to verify it by running the query. If it exists - merging, if not - are saved. This is really a hassle, but I have not yet seen a better solution.

EDIT2: the object you pass to the merge method will remain disconnected - the managed object will be returned to merge , so you will need to merge first, and then set the link to account to the returned merge value.

+3
source share

You cannot pass an object with data to save, there is no way. But you do not need.

You want to keep Account regardless of its AccountRole (which already exists). To achieve this, simply remove the cascade from @ManyToOne in the child entity (in this case, Account ):

 public class Account { private AccountRole accountRole; @ManyToOne // no cascading here! public AccountRole getAccountRole() { return accountRole; } 

See my explanation here, why: https://stackoverflow.com/a/166268/

0
source share

All Articles