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 ProjectDependencies 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.
Implements javax.persistence:javax.persistence-api version 2.1 - JDK 1.8
- Maven 3.3.9
|