Search code examples
hibernatejpaprojection

Hibernate Generating Unnecessary Queries When Using Nested Closed JPA Projections


I am running into a strange issue with JPA/Hibernate I hope I can get some help with. My environment:

  • OpenJDK 11.0.2 Spring Boot 2.2.2
  • spring-boot-starter-JPA (default version for above Spring Boot version)
  • Hibernate 5.4.9
  • Maria DB 2.3.0
  • Windows 10

I am using two Entities:

@Entity
@Table(name = "\"accUser\"") 
public class User implements Serializable {

    private static final long serialVersionUID = -5750077342980986498L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "UserID")
    private Long id;

    // NOTE: Below is an embedded object!
    @OneToOne
    @JoinColumn(name = "EmpNum")
    private Employee employee;

    //...other fields are wrapped primitives omitted for brevity
}

@Entity
@Table(name = "\"hrmEmployee\"")
public class Employee implements Serializable {
    private static final long serialVersionUID = 5471137977607643256L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "EmpNum")
    private Long employeeNumber;

    @Column(name = "FirstName")
    private String firstName;

    //...other fields are wrapped primitives omitted for brevity

}

I have the following (closed) Projection interfaces defined, each in their own class file:

@Projection(types={ User.class })
interface UserProjection {
    Long getId();
    EmployeeFirstNameProjection getEmployee();
}

@Projection(types={ Employee.class })
interface EmployeeFirstNameProjection {
    String getFirstName();
}

I am calling this Repository interface query method:

<T> T findUserById(Long id, Class <T> type);

And calling the above Repository method with this Service method:

public UserProjection getUser(Long id) {
    return userRepository.findUserById(id, UserProjection.class);
} 

So at runtime, here is the JSON of the single returned UserProjection:

{"employee":{"firstName":"Matt"},"id":1796}

This is exactly what I want to be returned. However, when the code executes, Hibernate is selecting all fields in both entities in two queries, which I don't want. The whole reason I am using the Projections mechanism is to limit wire traffic with the JSON, and also want to hopefully keep the number of queries low for performance reasons.

What I expect is to see a SINGLE Hibernate generated query.

Why is Hibernate running two respective queries that select every field in each of the entities?

Thanks in advance!


Solution

  • Hibernate and Spring-data are working as they should, when there is a non primitive field in the projection all the columns are included in the query.

    It was already explained here https://stackoverflow.com/a/53783270/3449039 and a jira was opened at that moment https://jira.spring.io/browse/DATAJPA-1218 and closed with this answer "Currently, we don't optimize the query for referenced entities by only selecting the required properties".

    As workaround you could create a JPQL query with a custom DTO or try something like Blaze-Persitence as was mentioned by @christian-beikov