In this article we are going to discuss the error about Hibernate Detached Entity Passed to Persist. Which is an error that occurs when trying to save an entity considered detached.
Let’s start by understanding what detached entities are.
Starting from Spring Boot 3 and Spring Framework 6, the error: org.hibernate.PersistentObjectException: detached entity passed to persist becomes the following org.hibernate.PersistentObjectExceptionto JPA
PersistenceException`: detached entity passed to persist.
What is a Detached Entity?
In the life cycle of entities in Hibernate, we go through 4 states, transient, managed, detached, and deleted.
A detached Entity is one of the Hibernate states. A detached entity is a POJO whose value corresponds to a row in the database.
We cause the entity to become detached when we close the session used to load it or when we call Session.clear() or Session.evict().
Why do we get the Detached Entity Passed to Persist exception?
The exception “org.hibernate.PersistentObjectException: detached entity passed to persist” or “org.hibernate.PersistentObjectExceptionto JPA
PersistenceException`: detached entity passed to persist” occurs when the session used to load the entity has been closed or Session.clear() or Session.evict() has been used.
Let’s see how we can cause the org.hibernate.PersistentObjectException: detached entity passed to persist exception based on a DepartmentEntity entity.
@Getter @Setter @Entity public class SingleDepartment { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String name; }
Let’s create a test based on the previous entity to cause the Hibernate exception: org.hibernate.PersistentObjectException: detached entity passed to persist:
@Test public void given_department_when_detach_a_single_to_change_name_then_exception() { singleDepartment = new SingleDepartment(); singleDepartment.setName("Accounts"); session.persist(singleDepartment); session.evict(singleDepartment); singleDepartment.setName("Accounts exception"); session.getTransaction().commit(); assertThatThrownBy(() -> session.persist(singleDepartment)).isInstanceOf( PersistenceException.class).hasMessageContaining( "org.hibernate.PersistentObjectException` to JPA `PersistenceException` : detached entity passed to persist: com.refactorizando.example.detachentity.entity.SingleDepartment"); }
How to fix the Detached Entity Passed to Persist exception?
Fix Hibernate’s detached entity passed to persist error by checking entity state and using correct Cascade type/method.
To fix it, we can use the following options that belong to JPA:
- Merge
Save: Deprecated starting from Spring Boot 3.SaveOrUpdate: Deprecated starting from Spring Boot 3.
@Test public void given_department_when_detach_a_single_entity_with_merge_then_saved() { singleDepartment = new SingleDepartment(); singleDepartment.setName("Accounts"); session.persist(singleDepartment); session.evict(singleDepartment); singleDepartment.setName("Accounts exception"); singleDepartment.setId(1L); session.merge(singleDepartment); session.getTransaction().commit(); Query querySaved = session.createQuery("Select e from SingleDepartment e where id= 1", SingleDepartment.class); singleDepartment = (SingleDepartment) querySaved.getSingleResult(); assertTrue("Accounts exception".equalsIgnoreCase(singleDepartment.getName())); }
Within the session class, we can see two more approaches like Persist and Merge that do not belong to JPA, so it is better to avoid them to use JPA’s own methods.
Detached Entity Passed to Persist exception with OneToMany relationship
Let’s continue with the Department example and let’s associate an Employee with a 1 .. N relationship.
@Getter @Setter @Entity public class Department { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String name; }
And now the Employee entity:
@Getter @Setter @Entity public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String name; @ManyToOne private Department department; }
Relationship uses Merge cascade type (CascadeType.Merge) to propagate merge operations only to the department.
Persisting employee requires prior merge on department in this approach.
@Test public void given_department_when_detach_a_employee_with_merge_then_saved() { Employee employee = new Employee(); employee.setName("Noel"); Department departmentMerge = session.merge(this.department); employee.setDepartment(departmentMerge); session.persist(employee); session.getTransaction().commit(); List<Employee> employees = session.createQuery("Select c from Employee c", Employee.class) .list(); assertEquals(employees.size(), 1); assertTrue(employees.get(0).getName().equalsIgnoreCase("Noel")); }
It should be noted that using persist in the relationship, if we apply Cascade ALL, will throw the exception: org.hibernate.PersistentObjectException: detached entity passed to persist, as we need to perform a merge on the entity first.
If, in the relationship between department and employee, we use persist instead of merge, we will get the error org.hibernate.PersistentObjectException to JPA PersistenceException: detached entity passed to persist:
@Test public void given_a_department_persist_when_new_employee_is_persist_then_exception_is_thrown() { department = new Department(); department.setName("Accounts"); session.persist(department); session.evict(department); department.setId(1L); Employee employee = new Employee(); employee.setDepartment(department); session.persist(employee); assertThatThrownBy(() -> session.persist(department)).isInstanceOf(PersistenceException.class) .hasMessageContaining( "org.hibernate.PersistentObjectException` to JPA `PersistenceException` : detached entity passed to persist: com.refactorizando.example.detachentity.entity.Department"); session.remove(employee); }
Conclusión
The title of this article Error in Hibernate Detached Entity Passed to Persist is a very common error that can occur in our applications with Hibernate. Knowing the different states and the lifecycle of Hibernate will help us better understand Hibernate errors.
In the case of Detached Entity, we will have to see how we are saving the entity or if we have closed the session before saving it, so we will have to use merge.
If you want to see an example where this error occurs, you can take a look at our Github.
If you need more information, you can leave us a comment or send an email to refactorizando.web@gmail.com You can also contact us through our social media channels on Facebook or twitter and we will be happy to assist you!!