Is there a way to pass detached object to JPA persist? (detached entity passed to persist)

detached entity passed to persist one to many
org.springframework.dao.invaliddataaccessapiusageexception: detached entity passed to persist:
jpa persist multiple entities
detached entity passed to persist many-to-many
jpa reattach entity
entitymanager merge list of entities
jpa save or update
attempt to persist detached object

I have 2 entities : 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;
    }

Problem comes when I take the accountRole from database and try to persist my Account. At this point I just created my account and 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: detached entity passed to persist And what I understood, I must set the entities values from both direction, so that what I am doing in my setter.

Still getting error.

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

Just replace the

entityManager.persist(account);

with:

entityManager.merge(account);

And allow merge cascading:

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

Because merge does this:

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

JPA Implementation Patterns: Saving (Detached) Entities, How would you reattach detached objects to a session when the same object has already been loaded into the session? This is because hibernate will imply that you are not trying to update old object, but you pass a new object to persist, whenever you change element on the child collection. Of course this solutions will not fit all applications and you should carefully design what you want to include in the equals and hashCode methods.

It looks like you leave the transaction during your processing, so the accountRole gets detached, or it is already detached for other reasons.

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

EDIT: Unfortunately, if you cannot be sure if the accountRole already exists in the DB, you will have to check it by querying. If it exists - merge, if not - persist. It is indeed a hassle, but I have not yet seen a better workaround.

EDIT2: The entity you pass to the merge method will remain detached - the managed entity will be returned by the merge, so you would need to merge first, then set the reference on the account to the return value of the merge.

Difference between Transient, Persistent, and Detached Objects in , We just pass the object we want to persist to EntityManager.persist. until we run into the dreaded “detached entity passed to persist” message. where the simplistic way EntityManager.merge copies the object state into the  The contract for persist (see section 3.2.1 of the JPA 1.0 spec) explicitly states that an EntityExistsException is thrown by the persist method when the object passed in is a detached entity. Or

You cannot pass a datached entity to persist, there is no way. But you don't need to.

You want to persist an Account independently of the AccountRole(which is already persisted). In order to achieve this, simply remove cascading from @ManyToOne in the child entity (Account in this case):

public class Account {
    private AccountRole accountRole;

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

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

What is the proper way to re-attach detached objects in Hibernate , This is a standard bidirectional compatibility problem. It is well discussed in this link as well as this link. As per the provisions in the previous 2  The contract for persist (see section 3.2.1 of the JPA 1.0 spec) explicitly states that an EntityExistsException is thrown by the persist method when the object passed in is a detached entity. Or any other PersistenceException when the persistence context is flushed or the transaction is committed.

JPA implementation patterns: Saving (detached) entities, We just pass the object we want to persist to EntityManager.persist. well until we run into the dreaded "detached entity passed to persist" message. the way one can simply invoke EntityManager.persist on an object (even  Retrieval by navigation from detached objects is not supported, so only persistent fields that have been loaded before detachment should be used. Changes to detached entity objects are not stored in the database unless modified detached objects are merged back into an EntityManager to become managed again.

JPA/Hibernate: detached entity passed to persist, The object models are complex, with lots of nested objects. Today's inscrutable message, "detached entity passed to persist", doesn't make much JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80) ~[​hibernate-entitymanager-5.0.12. With cascade.merge it is the other way around​. One of the complicated issue while working with Hibernate / JPA projects are that differentiating the state of persistent objects. If you no longer required an object, programatically one can detach an entity from the transaction and it will be no longer in the persistence state.

A fix for "Persistent Object Exception, Explains detached entity objects and how to work with detached objects in JPA, including merging them into an EntityManager. Changes to detached entity objects are not stored in the database unless modified detached objects are merged back into an s persistence context and detach all managed entity objects:. Understand 'detached entity passed to persist' error with @ManyToMany JPA relation In a JPA many to many relationship, if cascade type has been set at CascadeType.PERSIST (or CascadeType.ALL, which includes CascadeType.PERSIST), then while saving the parent and updating it with references of the child, it will try to save the child again.

Comments
  • Also note that, persist() will make the object you passed a managed entity, however, merge will return a managed copy of the object of you passed. So if you need a managed entity after merge you should do account = entityManager.merge(account) Also take a look here
  • in rare occasions the AccountRole does not exist in database, so when doing em.persist, it persists the account and accountrole, and everything works. now when I find myself in that case with your code, it is trying to add the AccountRole twice to database, first with merge, with succeedes and then with persist also, thus giving me duplicate key value violation error, any suggestions? problem is that, sometimes the role does not exist.
  • one solution could be that, if Role does not exist, persist the whole damn thing, but if role does exist, merge it first, but that seems like too much of a hassle, doesn't it?
  • @Jaanus - alas, you are correct :) I have edited the answer accordingly.
  • just tried that, same thing.. entityManager.merge(account.getAccountRole()); entityManager.persist(account); and same error : detached entity passed to persist: ee.sellin.vahvagame.pojo.AccountRole .. oh boy
  • @Jaanus - there is a quirk in JPA with merging - I forgot to mention it, sorry. See second edit.