76

I have a java EE project using JPA (transaction-type="JTA"), hibernate as provider. I write my beans to handle the CRUD things. The program running in JBOSS 7 AS.

I have an EntityManagerDAO :

@Stateful
public class EntityManagerDao implements Serializable {

    @PersistenceContext(unitName = "dtdJpa")
    private EntityManager entityManager;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public Object updateObject(Object object) {
        object = entityManager.merge(object);
        return object;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void createObject(Object object) {
        entityManager.persist(object);
    }

    public void refresh(Object object) {
        entityManager.refresh(object);
    }

    public <T> T find(Class<T> clazz, Long id) {
        return entityManager.find(clazz, id);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void deleteObject(Object object) {
        entityManager.remove(object);
    }
}

but when I invoke deleteObject, this exception comes out.

java.lang.IllegalArgumentException: Removing a detached instance com.test.User#5

How is this caused and how can I solve it?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
neptune
  • 875
  • 1
  • 7
  • 8

5 Answers5

246

EntityManager#remove() works only on entities which are managed in the current transaction/context. In your case, you're retrieving the entity in an earlier transaction, storing it in the HTTP session and then attempting to remove it in a different transaction/context. This just won't work.

You need to check if the entity is managed by EntityManager#contains() and if not, then make it managed it EntityManager#merge().

Basically, the delete() method of your business service class should look like this:

em.remove(em.contains(entity) ? entity : em.merge(entity));
DavidR
  • 6,622
  • 13
  • 56
  • 70
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • @BalusC In em.remove(em.contains(entity) ? entity : em.merge(entity)); , if em(contains(entity) is false then are you removing entityToBeRemoved = em.merge(entity) , entityToBeRemoved? Are you removing what returns from em.merge(entity) ? – Koray Tugay Jul 20 '13 at 20:48
  • Because according to the answer in the question I mentioned you need: a = em.merge(a); // merge and assign a to the attached entity em.remove(a); // remove the attached entity – Koray Tugay Jul 20 '13 at 20:53
  • @BalusC In using em.remove(em.contains(entity) ? entity : em.merge(entity)); are there any dangers related. Because I was getting this error and I changed to your solution and it works. But the Java experts on my team are not so sure. – ITguy Nov 11 '16 at 14:39
  • 3
    @BalusC Will `em.remove(em.getReference(...))` also work? – Jin Kwon Jan 20 '17 at 05:19
  • 1
    @BalusC man.. you are a genius. I had the same issue. but I moved my transaction to service layer and fixed my problem. Actually my case was a bit different, from the UI I was getting just the ID of the user, so In my service I was making 2 calls to the DB. One to check if the user exists and the second to delete. Since Transaction was at the DAO layer as you said it was a separate transaction. So i moved it to Service layer and it worked.. thanks again for the clear explanation. – user641887 Oct 05 '17 at 23:04
  • I think this answer can be improved if the phrase entityManager.close is also mentioned here :D – Artanis Zeratul Dec 10 '18 at 20:20
  • In case this burns anyone else, it's important to remove() the object that was merged. I'm green with Hibernate, so I mistakenly thought the merge mutated the object and then you suddenly had a managed object. This apparently is not so. – Woodsman Sep 19 '22 at 15:09
4

In my case, I got the same error, when I tried to delete an object using,

session.delete(obj)

without creating any transaction before that.

And the problem is solved by creating the transaction first(session.beginTransaction() and then deleting the object.

I hope my answer will help someone :)

Rajesh
  • 1,911
  • 1
  • 22
  • 19
1

Sometimes its simply because you are missing the @Transaction annotation for add, remove, update operations.

0

I faced the same problem. The detached entity should be re-attached. As @BalusC mentioned, using EntityManager.merge() should be used to attach the detached entity. EntityManager.merge() generates SQL Query which fetches the current state of the entity, on which EntityManager.remove() has to be performed. But in my case it didn't worked. Try EntityManager.remove(EntityManager.find(Class<T>,arg)) instead. It worked for me.

Hadi
  • 36,233
  • 13
  • 65
  • 124
0

In my experience, if I query an object from the DB then closed the entity manager then do a DB delete, the problem happens. Or if I copy that loaded object to another instance then do a delete, this problem also happens. In my opinion there are 2 things to keep note:

  • The object must be in the same session that was created by the Entity Manager
  • And the object mustn't be transferred to another object while the Entity Manager's session is still opened.

Cheers

Artanis Zeratul
  • 963
  • 2
  • 14
  • 40