Reputation: 537
Implemented one to many relationship and it is working fine.
My issue is when i run the below query, if the table has 100 employee rows, and each employee has 2 departments. The database query is called 101 times, because for each employee it is calling department query, it is taking very long to complete calling all hundred rows, can any one suggest any alternative solution?
Please see the details below
Queries it is calling:
First query is : SELECT * FROM Employee e
Next 100 queries : SELECT * FROM DEPARTMENT d WHERE d.EmployeeId=?
JPA Database call :
javax.persistence.Query query = em.createNamedQuery("SELECT * FROM Employee e", Employee.class);
return query.getResultList();
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "EMPLOYEE")
public class Employee implements Serializable
{
@Id
@Column(name = "EmployeeId")
String employeeId;
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Department> departments;
public List<Department> getDepartments() {
return departments;
}
public void setDepartments(List<Department> departments) {
this.departments = departments;
}
public String getEmployeeId() {
return employeeId;
}
public void setEmployeeId(String employeeId) {
this.employeeId = employeeId;
}
}
@Entity
@Table(name = "DEPARTMENT")
public class Department implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "DepartmentID")
String departmentId;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "EmployeeId", insertable = false, updatable = false)
private Employee employee;
}
The output xml:
<Employees>
<Employee>
<name>Rob</name>
<Departments>
<Departmnet><id>1</id></Departmnet>
<Departmnet><id>2</id></Departmnet>
</Departments>
</Employee>
<Employee>
<name>Sam</name>
<Departments>
<Departmnet><id>1</id></Departmnet>
<Departmnet><id>2</id></Departmnet>
</Departments>
</Employee>
</Employees>
Upvotes: 5
Views: 22013
Reputation: 1203
Classic N+1 problem. You can reduce number of queries with Batch Fetching which just combines many lazy sql clauses to single one.
For Example:
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@BatchSize(size=10)
private List<Department> departments;
Upvotes: 2
Reputation: 4124
This is a typical N+1 selects issue. I usually solve this with JOIN FETCH
queries as described here and here
Upvotes: 4
Reputation: 8561
Change FetchType.EAGER
to FetchType.LAZY
. Load the departments only when you need them which is looping the employee.getDepartmentList() for example
for(Department dept:employeeGetDepartmentList()){
dept.getId();
}
before using departments
Upvotes: 2
Reputation: 94489
You could switch the fetchtype to lazy, which will cause the departments only to be queried when necessary.
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Department> departments;
Upvotes: 2