We have an Employee class with the following structure:
class Employee {
Long empId;
String fname;
String lname;
String designation;
String client;
String status; // Active, Terminated
LocalDateTime modifiedDate;
List<Employee> reportingEmps; // LAZY fetch
Employee manager;
}
When a manager is terminated, we want to terminate all employees reporting to them. However, since reportingEmps is marked as LAZY fetch, we are encountering an exception when trying to access the reporting employees. What is the exception, and how can it be resolved?
Answer:
The exception being encountered is:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
This happens because the reportingEmps collection is lazily loaded, and you are trying to access it outside of the Hibernate session or persistence context. Since the session is closed by the time the collection is accessed, Hibernate cannot fetch the data and throws this exception.
Solutions:
- Use
@TransactionalAnnotation: Ensure that the method where you accessreportingEmpsis annotated with@Transactionalso that the session remains open:
@Transactional
public void terminateManagerAndReportees(Long managerId) {
Employee manager = employeeRepository.findById(managerId).orElseThrow();
manager.setStatus("Terminated");
for (Employee emp : manager.getReportingEmps()) {
emp.setStatus("Terminated");
}
employeeRepository.save(manager);
}
- Use JPQL with JOIN FETCH: Modify your repository to fetch the lazy collection explicitly:
@Query("SELECT m FROM Employee m LEFT JOIN FETCH m.reportingEmps WHERE m.empId = :id")
Employee findManagerWithReportees(@Param("id") Long id);
Then use this method to retrieve the manager:
Employee manager = employeeRepository.findManagerWithReportees(managerId);
- Manually Initialize the Collection: You can use
Hibernate.initialize()to force load the lazy collection inside a transaction:
@Transactional
public void terminateManager(Long managerId) {
Employee manager = employeeRepository.findById(managerId).orElseThrow();
Hibernate.initialize(manager.getReportingEmps());
// Proceed with termination
}
Best Practice:
The preferred approach is to keep the logic within a @Transactional method to ensure the Hibernate session remains open, allowing lazy loading to work as intended.