0

My question is regarding how to correctly handle the LazyInitializationException in an 1:N relation.

Considering the two following classes:

  1. 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

  1. either setting FetchType.EAGER to the employees Set
@OneToMany(fetch = FetchType.EAGER)
private Set<Employee> employees;
  1. 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.

IdealOutage
  • 145
  • 1
  • 1
  • 9

0 Answers0