Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding how spring-data handles @EntityGraph

(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 Companywithout 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 @NamedEntityGraphon 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?

like image 872
Arnaud Denoyelle Avatar asked Nov 07 '16 22:11

Arnaud Denoyelle


People also ask

How does Spring data Work?

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.

What is spring data and why it more powerful?

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.

What is correct about Spring data JP A?

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.

What is entity graph in Spring data JPA?

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.


2 Answers

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.

like image 93
Dragan Bozanovic Avatar answered Oct 02 '22 14:10

Dragan Bozanovic


Modified Answer

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.

like image 20
xsalefter Avatar answered Oct 02 '22 13:10

xsalefter