AdBlock Detected

It looks like you're using an ad-blocker!

Our team work realy hard to produce quality content on this website and we noticed you have ad-blocking enabled. Advertisements and advertising enable us to continue working and provide high-quality content.

detached-entity-passed-to-persist

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 JPAPersistenceException`: 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 JPAPersistenceException`: 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!!

Leave a Reply

Your email address will not be published. Required fields are marked *