1. Overview

In this article, We will learn Spring JPA Projection example using interface and class. Projection means select only specific column instead of fetching all the columns from the table. Spring JPA provides projection using Interface as well as class.

Projection is always the good practice because selecting only specific columns will improve the performance of the application.

Here is an example of implements JPA in spring boot application, in this article, we have considered the only repository layer for more readable and clean code.

2. Spring JPA Projection using Interface

1. Close Projection

Here we have defined an interface which contains methods which are matching with properties name.

EmployeeBasicDetails.java

package com.javadeveloperzone.model;
public interface EmployeeBasicDetails {
    String getEmployeeName();
    String getEmployeeId();
}

Projection in the @Query annotation and method query

The close projection will fetch all the matching properties columns which are defined in the interface.

@Repository
@Transactional
public interface EmployeeDAO extends org.springframework.data.repository.Repository<Employee,Integer> {
   @Query("SELECT e.employeeName as employeeName,e.employeeRole as employeeRole FROM Employee e")  // JPA projection using query
   List<EmployeeBasicDetails> getEmployeeBasicDetails();
   List<EmployeeBasicDetails> findAllByEmployeeName(String name);  // JPA projection using method name 
}

Query:

SELECT employeeId, employeeName FROM employee WHERE employeeName=?

2. Open Projection

When we used @Value annotation inside interface then it is known as open projection.

NOTE: When we used option projection then Spring JPA will fetch all the columns, It will not optimize the query by only selecting specific columns because we can use any columns in the @Value annotation. Here are more details about open projections.

We are as define an interface and define getBasicDetails() with @Value annotation, Inside @Value annotation we can use any properties of Entity not only those which are defined in the interface.

EmployeeBasicDetails.java

package com.javadeveloperzone.model;
import org.springframework.beans.factory.annotation.Value;
public interface EmployeeBasicDetails {
    String getEmployeeName();
    String getEmployeeId();
    @Value("#{target.employeeName + ' ' + target.employeeRole}")
    String getBasicDetails();
}

EmployeeDAO.java

@Repository @Transactional 
public interface EmployeeDAO extends org.springframework.data.repository.Repository<Employee,Integer> { 
    List<EmployeeBasicDetails> findAllByEmployeeName(String name);
}

Query:

SELECT employeeId, employeeName FROM employee WHERE employeeName=?

3. Runtime projection

Spring data JPA also support runtime projection based on pass class or interface projection will be applied.

EmployeeBasicDetails.java

package com.javadeveloperzone.model;
public interface EmployeeBasicDetails {
    String getEmployeeName();
    String getEmployeeId();
}

EmployeeNamesDetails.java

package com.javadeveloperzone.model;
public interface EmployeeNamesDetails {
    String getEmployeeName();
}

EmployeeDAO.java

@Repository
@Transactional
public interface EmployeeDAO extends org.springframework.data.repository.Repository<Employee,Integer> {
<T> List<T> findAllByEmployeeName(String name,Class<T> type);
}

Query:

SELECT employeeId, employeeName, employeeRole FROM employee WHERE employeeName=?

Output:

employeeDAO.findAllByEmployeeName("Jone", EmployeeBasicDetails.class).forEach((v)->{
    System.out.println(v.getEmployeeName());
    System.out.println(v.getEmployeeId());
});
employeeDAO.findAllByEmployeeName("Jone", EmployeeNamesDetails.class).forEach((v)->{
    System.out.println(v.getEmployeeName());
});

2. Spring JPA Projection using Class

While working projection using Class make sure that requires to define the proper public constructor with all the fields. Otherwise, Spring JPA will generate runtime error like : org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class

public class EmployeeBasicDetails {
    private final String employeeName;
    private final int employeeId;
    public EmployeeBasicDetails(int employeeId,String employeeName){
        this.employeeId=employeeId;
        this.employeeName=employeeName;
    }
    public int getEmployeeId() {
        return employeeId;
    }
    public String getEmployeeName() {
        return employeeName;
    }
}

EmployeeDAO.java

@Repository
@Transactional
public interface EmployeeDAO extends org.springframework.data.repository.Repository<Employee,Integer> {
      List<EmployeeBasicDetails> findAllByEmployeeName(String name);
}

Query:

SELECT employeeId, employeeName FROM employee WHERE employeeName=?

3. Conclusion

In this article, we learned about different ways to apply projection in Spring Data JPA like projection using interface and class. while interface has two ways of projection: open and close projection.

4. References

Was this post helpful?

1 comment. Leave new

Need more explanation about JPA Projection.

Leave a Reply

Your email address will not be published. Required fields are marked *