Search code examples
javajpaentityopenjpa

Understanding: "Cannot perform operation delete on detached object"


Following Entity throws and Error when deleting:

Entity:

@Entity
@NamedQueries({
})
public class Server {
   //some attributes
}

I have following quite simple JUnit test that performs the following operations:

  1. Entity Server is created
    @Transactional
    public class ServerDao {
    public Server update(Server entity, long userId) {
        entity.setDeleted(false);
        if (entity.getId() > 0) {
            if (userId > 0) {
                entity.setUpdated(new Date());
                entity.setUpdatedby(usersDao.get(userId));
            }
            em.merge(entity);
        } else {
            if (userId > 0) {
                entity.setInserted(new Date());
                entity.setInsertedby(usersDao.get(userId));
            }
            em.persist(entity);
        }
        return entity;
        }
    }
    
  2. Entity Server is deleted

    ... same Dao

    public void deleteHardJUnit(Server entity) {
        em.remove(entity);
    }
    

    This will throw an exception like:

org.apache.openjpa.persistence.ArgumentException: You cannot perform operation delete on detached object "org.apache.openmeetings.persistence.beans.basic.Server-1".

If I change the delete method to:

public void deleteHardJUnit(Server entity) {
    if (entity.getId() > 0) {
        em.refresh(entity);
        em.remove(entity);
    }
}

Everything "seems" to work as expected, no exception is thrown and the record is deleted from the database.

However I am not sure what this should mean, do we really need to refresh every entity before deleting it? Cause I have been using EntityManager.delete a number of times before without the need to refresh the entity.


Solution

  • Assuming you're using Spring's @Transactional annotation, it can't intercept calls coming from within an instance of the annotated object (due to Spring's use of dynamic proxies for AOP and method interception). Try calling from a service layer and annotating the method there.

    If you're not using Spring, then you likely want to be using @TransactionAttribute, which is the analagous Java EE annotation.