Rahul
Rahul

Reputation: 45040

Resolving the JPA/Hibernate EntityNotFoundException

I've run into a very weird situation here. When I try to delete a set of entities & immediately later try to add another set of entities, which may or may not have the same elements again,I seem to be getting the below exception. The whole stack trace isn't required as it doesn't say much.

javax.persistence.EntityNotFoundException: deleted entity passed to persist [com.test.MyEntity#<null>]

To make myself more clear, let me give a more detailed explanation.

This is my Entity.

@Entity
@Table(name = "MY_ENTITY")
@SequenceGenerator(name = "my_enty_seq", sequenceName = "MY_ENTITY_SEQ")
public class MyEntity {

    private long id;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "my_enty_seq")
    @Column(name = "ID", unique = true, nullable = false, precision = 12, scale = 0)
    public long getId() {
        return this.id;
    }

    // Other methods & variables which are not relevant here.
}

And this is the class playing with the entities.

public class MyEntityServiceImpl implements MyEntityService {

    public void updateMyEntities(List<MyEntity> newEntities) {

        // Delete the Old Items
        List<MyEntity> oldEntities = myDAO.getAllEntities();
        myDAO.delete(oldEntities); // myDAO extends GenericDaoJpaWithoutJpaTemplate, hence, the DELETE is available in it.

        // Add the New Items
        myDAO.store(newEntities); // This is where I get the mentioned Exception.
    }

    // Other non-relevant stuffs
}

The scenario where I get the mentioned exception on the store() method is when there is some common MyEntity object, present in both the oldEntities and newEntities lists.

I've tried quite a few things to make this work, but nothing could help me overcome the problem. Adding FetchType.EAGER & CascaseType.ALL, CascaseType.PERSIST also didn't work. The jpa EntityManager doesn't seem to have a commit() method either, which I could use after the delete() & before the store() method. I've tried interchanging store() with persist()(though store internally calls persist()) too!

Note:- The requirement is to delete the old list and insert the fresh list, as comparing the elements and adding only the new ones is tedious(the list can be pretty huge at times).

Upvotes: 0

Views: 1924

Answers (2)

Rahul
Rahul

Reputation: 45040

I've figured out a way for this. I used the flushAndClear() method instead of the flush() method.

It seems the flush() only synchronized the persistence cache with the DB but the did not clear it.

flushAndClear() on the other hand performs all the pending operations and then clears everthing.

Quoting from a java doc present in source code of the org.crank.crud.GenericDao<T, PK extends Serializable> for the delete method,

Remove an object from persistent storage in the database. Since this uses the PK to do the delete there is a chance that the entity manager could be left in an inconsistent state, if you delete the object with id 1 but that object is still in the entity managers cache.

You can do two things, put all your PK deletes together and then call flushAndClear when done, or you can just call the delete method with the entity which will not suffer from this problem.

I tried the first option of using the flushAndClear() method and it worked as expected.

Upvotes: 0

Jens Schauder
Jens Schauder

Reputation: 81862

The exception is quite clear I think: You told the session to delete entity X and at the same time store entity X. Now the poor thing is confused and doesn't know what to do.

Do a Session.flush() possibly via a commit before persisting the new/old/deleted entity.

Edit:

If this doesn't do the trick, you need to do the insert in a new session. Problem might still be, that you don't have a transient entity, but one actually deleted. So you might have to copy all your data into a new instance.

Upvotes: 2

Related Questions