(I made a SSCCE for this question.)
I have 2 simple entities : Employee
and Company
. Employee
has a @ManyToOne
relationship with Company
with default fetch strategy (eager).
I want to be able to load the Employee
without the Company
without changing the fetch strategy defined in the Employee
because I need to do that for only one use case.
JPA's entity graph seems to be intended for this purpose.
So I defined a @NamedEntityGraph
on the class Employee
:
@Entity
@NamedEntityGraph(name = "employeeOnly")
public class Employee {
@Id
private Integer id;
private String name;
private String surname;
@ManyToOne
private Company company;
//Getters & Setters
And a EmployeeRepository
like this :
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
@EntityGraph(value = "employeeOnly", type = EntityGraph.EntityGraphType.FETCH)
List<Employee> findByCompanyId(Integer companyId);
}
Despite the use of @EntityGraph
, I can see in the logs that the Company
is still loaded by hibernate :
2016-11-07 23:16:08.738 DEBUG 1029 --- [nio-8080-exec-2] org.hibernate.SQL : select employee0_.id as id1_1_, employee0_.company_id as company_4_1_, employee0_.name as name2_1_, employee0_.surname as surname3_1_ from employee employee0_ left outer join company company1_ on employee0_.company_id=company1_.id where company1_.id=?
2016-11-07 23:16:08.744 DEBUG 1029 --- [nio-8080-exec-2] org.hibernate.SQL : select company0_.id as id1_0_0_, company0_.name as name2_0_0_ from company company0_ where company0_.id=?
Why? How to avoid that?
The Spring Data JPA framework can then inspect that contract, and automatically build the interface implementation under the covers for you. For Spring Data JPA to intelligently generate an implementation of your Repository interface, a Query DSL is needed. DSL is an acronym for Domain Specific Language.
Spring Data is a high level SpringSource project whose purpose is to unify and ease the access to different kinds of persistence stores, both relational database systems and NoSQL data stores.
Spring Data JPA is an add-onIt provides a framework that works with JPA and provides a complete abstraction over the Data Access Layer. Spring Data JPA brings in the concept of JPA Repositories, a set of Interfaces that defines query methods. The Repository and Entity Bean represent the DAO layer in the application.
JPA 2.1 has introduced the Entity Graph feature as a more sophisticated method of dealing with performance loading. It allows defining a template by grouping the related persistence fields which we want to retrieve and lets us choose the graph type at runtime.
Currently, Hibernate does not support handling non-lazy attributes as lazy, even with entity graphs. There is an open issue for this: HHH-8776.
So, the only solution for the time being is to make the association lazy.
per-specification, the fetch type for @ManyToOne
is EAGER
by default. But even through we set:
@ManyToOne(fetch = FetchType.LAZY)
private Company company;
You will get the same result. The problem because the way spring-data-jpa create HQL/JPQL for you. So adding @ManyToOne(fetch = FetchType.LAZY)
won't work is not enough. To solve this, use@ManyToOne(fetch = FetchType.LAZY)
and @Query
annotation in your repository:
Employee.java :
@ManyToOne(fetch = FetchType.LAZY)
private Company company;
EmployeeRepository.java
@Query("from Employee e where e.company.id = :companyId")
List<Employee> findByCompanyIdUsingQuery(@Param("companyId") Integer companyId);
In the test, this is SQL that generated by your loadByCompanyId()
(which is generate left outer join):
select employee0_.id as id1_1_, employee0_.company_id as company_4_1_, employee0_.name as name2_1_, employee0_.surname as surname3_1_ from employee employee0_ left outer join company company1_ on employee0_.company_id=company1_.id where company1_.id=?
And this is SQL generated by method that use @Query
annotation:
select employee0_.id as id1_1_, employee0_.company_id as company_4_1_, employee0_.name as name2_1_, employee0_.surname as surname3_1_ from employee employee0_ where employee0_.company_id=?
You could check the latest code in my repository.
HTH.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With