My question is regarding how to correctly handle the LazyInitializationException in an 1:N relation.
Considering the two following classes:
- Company.java
@Entity
@NoArgsConstructor
@Getter
@Setter
public class Company {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany
private Set<Employee> employees;
public Company(String name) {
this.name = name;
}
public void addEmployee(Employee v) {
this.employees.add(v);
v.setCompany(this);
}
}
and 2. Employee.java
@Entity
@NoArgsConstructor
@Getter
@Setter
public class Employee {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
private Company company;
public Employee(String name) {
this.name = name;
}
}
the following code in an imaginary CompanyService will throw a org.hibernate.LazyInitializationException, since Set<Employee> employees is fetched lazily by default.
public void addEmployee(Long companyId, String name) {
// get company by id
Company company = this.companyRepository.findById(companyId).orElseThrow(IllegalArgumentException::new);
// create new employee and add to company
Employee employee = new Employee(name);
company.addEmployee(employee); // <- org.hibernate.LazyInitializationException is thrown here
// save both
this.employeeRepository.save(employee);
this.companyRepository.save(company);
}
However, now my question is, what is the recommended way to handle this case? Solutions I've found are
- either setting FetchType.EAGER to the employees Set
@OneToMany(fetch = FetchType.EAGER)
private Set<Employee> employees;
- or marking the method addEmployee as @Transactional
@Transactional
public void addEmployee(Long companyId, String name) {
// get company by id
Company company = this.companyRepository.findById(companyId).orElseThrow(IllegalArgumentException::new);
// create new employee and add to company
Employee employee = new Employee(name);
company.addEmployee(employee);
// save both
this.employeeRepository.save(employee);
this.companyRepository.save(company);
}
However, both of those solutions don't feel correct. Especially FetchType.EAGER, since there might be cases where I want to get a company without the employees. Hence my question, which of those two solutions is the recommended one or is there another solution, that I have missed completely?
Edit: I went with the @Transactional functionality to annotate individual methods in my Service that require lazily fetched child entities.