Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA EntityManager persist() causing object to appear detached even though an error was thrown

Hi I have a simple DAO with the below function.

    public element createElement(Element e){

    em.persist(e);
    em.flush();

    return e;
}

The Entity table has a unique constraint on the pair (type,value) and I have a test below:

    public void testCreateElement() throws DataAccessException {
        // Start with empty Element table

        Element e = new Element();
        e.setType(myType.OTHER);
        e.setValue("1");
        dao.createElement(e);

        e = new Element();
        e.setType(MyType.OTHER);
        e.setValue("1");
        try{
                // this should violate unique constraint of database.
                dao.createElement(e);
        } catch (Exception ex) {
            System.out.println(ex);
        }

        e.setValue("2");
        try{
            // I expect this to work as there is no element with these values.
            dao.createElement(e);
        } catch (Exception ex) {
            System.out.println(ex);
        }
    }

My first caught error happens as I expect since I know that I'm violating the constraint, the second try/catch shouldn't throw an error as far as i'm concerned, but it does, what I get its this:

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.mypackage.Element

So it seems calling persist() on "e" even though it wasn't persisted has caused hibernate to think it's a detached entity.

This is annoying because these functions are getting used by a JSF front end that is dealing with the ConstraintViolation exception, but deliberately holding on to the object so that the user can change one of the fields and try again, and they get the detached entity error.

Is this behaviour a hibernate bug because I don't think it should be doing this really? Is there a way around this at the DAO level so that persist won;t treat my object as detached if it's not actually persisted?

Regards,

Glen x

like image 377
Link19 Avatar asked Feb 24 '12 16:02

Link19


1 Answers

An exception thrown by Hibernate is not recoverable. The only thing you should ever do when such an exception occurs is rollback the transaction and close the session. The state of the session (and its entities) after such an exception is unstable.

If you want to keep a copy of the element untouched, use merge() rather than persist(), or clone the element before persisting it.

Note that the exception is expected, since when Hibernate persists and flushes the entity, it starts by generating an ID and assigning the ID to the entity, then inserts the row, which causes the exception. So, after the exception, the entity has an ID assigned, and is thus considered as a detached entity by Hibernate. You could try resetting the ID to null and see if it works, but I would prefer cloning the entity before or using merge.

like image 183
JB Nizet Avatar answered Sep 26 '22 14:09

JB Nizet