JPA - Using PersistenceUtil.isLoaded() and EntityManager.contains() to load lazy attributes of a detached entity

[Updated: Dec 9, 2017, Created: Dec 7, 2017]

In last tutorial we saw how to use javax.persistence.PersistenceUtil.isLoaded() method to find out the load state of an entity or entity attributes. Following example shows how to use isLoaded() and EntityManager.contains() methods to initialize lazy attributes of a detached entity.

Example

The Entities

@Entity
public class Employee {
  @Id
  @GeneratedValue
  private Integer id;
  private String name;
  private String department;
  @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  private List<Phone> phones;
    .............
}
@Entity
public class Phone {
  @Id
  @GeneratedValue
  private int id;
  private String number;
  private String type;
    .............
}

Accessing Lazy fields of a detached entity

Following example uses a global instance of EntityManager.

In displayInGui() method, we are attempting to access uninitialized attributes of the employee entity:

public class LoadStateAndDetachEntityExample {
  static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");
  static EntityManager entityManager = entityManagerFactory.createEntityManager();

  public static void main(String[] args) {
      try {
          persistEmployee();
          Employee employee = findEmployeeById(1);
          displayInGui(employee);
      } finally {
          entityManagerFactory.close();
      }
  }

  private static void displayInGui(Employee employee) {
      System.out.println("-- displaying employee --");
      System.out.println(employee);
      employee.getPhones()
              .forEach(System.out::println);
  }

  private static Employee findEmployeeById(int id) {
      Employee employee = entityManager.find(Employee.class, id);
      //detach to remove it from entityManager cache
      entityManager.detach(employee);
      return employee;
  }

 private static void persistEmployee() {
      Employee employee = new Employee("Joe", "IT",
              Phone.cell("111-111-1111"), Phone.work("222-222-2222"));
      entityManager.getTransaction().begin();
      entityManager.persist(employee);
      entityManager.getTransaction().commit();
      //detach to remove it from entityManager cache
      entityManager.detach(employee);
  }
}
-- displaying employee --
Employee{id=1, name='Joe', department='IT'}
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.logicbig.example.Employee.phones, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:582)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:201)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:561)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:132)
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:277)
at java.lang.Iterable.forEach(Iterable.java:74)
at com.logicbig.example.LoadStateAndDetachEntityExample.displayInGui(LoadStateAndDetachEntityExample.java:26)
at com.logicbig.example.LoadStateAndDetachEntityExample.main(LoadStateAndDetachEntityExample.java:16)

To fix above exception, we need to conditionally merge and initialize the lazy fields of the employee entity.

public class LoadStateAndDetachEntityExample2 {
  static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");
  static EntityManager entityManager = entityManagerFactory.createEntityManager();

  public static void main(String[] args) {
      try {
          persistEmployee();
          Employee employee = findEmployeeById(1);
          displayInGui(employee);
      } finally {
          entityManagerFactory.close();
      }
  }

  private static void displayInGui(Employee employee) {
      employee = checkAndInitialize(employee);
      System.out.println("-- displaying employee --");
      System.out.println(employee);
      employee.getPhones()
              .forEach(System.out::println);
  }

  private static Employee checkAndInitialize(Employee employee) {
      PersistenceUtil pu = entityManagerFactory.getPersistenceUnitUtil();
      System.out.println("       Employee loaded: " + pu.isLoaded(employee));
      System.out.println("Employee.phones loaded: " + pu.isLoaded(employee, "phones"));
      if (!pu.isLoaded(employee) //entity might've been retrieved via getReference
              || !pu.isLoaded(employee, "phones")//phones is a lazy relation
              ) {
          System.out.println("initializing employee");
          boolean detached = !entityManager.contains(employee);
          System.out.println("is employee detached: " + detached);
          if (detached) {
              System.out.println("merging employee");
              employee = entityManager.merge(employee);
          }
          //this will load/initialize employee entity
          employee.getName();
          employee.getDepartment();
          //this will load lazy phones field
          employee.getPhones().size();
          entityManager.detach(employee);
          //now employee is fully initialized
          System.out.println("employee initialized");
      }
      return employee;
  }
    .............
}
       Employee loaded: true
Employee.phones loaded: false
initializing employee
is employee detached: true
merging employee
employee initialized
-- displaying employee --
Employee{id=1, name='Joe', department='IT'}
Phone{id=2, number='111-111-1111', type='cell'}
Phone{id=3, number='222-222-2222', type='work'}

Example Project

Dependencies and Technologies Used :

  • h2 1.4.196: H2 Database Engine.
  • hibernate-core 5.2.10.Final: The core O/RM functionality as provided by Hibernate.
  • JDK 1.8
  • Maven 3.3.9

PersistenceUtil.isLoaded() Examples Select All Download
  • use-load-state-scenario-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
          • META-INF

See Also