Advertisement

Google Ad Slot: content-top

Spring Boot JPA Projection (Fetching Specific Columns)

~1 min read · Spring Boot
On this page

Projection in Spring Boot JPA allows you to fetch specific columns from a table instead of the entire entity. This improves performance by reducing data transfer.


Using Interface-Based Projection

The simplest way to fetch specific columns is by defining an interface projection


Example: Fetching Only id and name from User

User.java
@Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; private int age; // Getters and Setters }
Define a Projection Interface
public interface UserProjection { Long getId(); String getName(); }
Modify Repository to Use Projection
public interface UserRepository extends JpaRepository { // Fetch only id and name List findByAgeGreaterThan(int age); }
Fetch Data in Service Layer
@Service public class UserService { @Autowired private UserRepository userRepository; public List getUsersByAge(int age) { return userRepository.findByAgeGreaterThan(age); } }
Response JSON (Example)
[ { "id": 1, "name": "John" }, { "id": 2, "name": "Sathish" } ]

Advantage:Faster than fetching the entire entity.


Using JPQL with Projection

If you need custom queries, you can use JPQL.

Modify Repository with @Query
public interface UserRepository extends JpaRepository { @Query("SELECT u.id, u.name FROM User u WHERE u.age > :age") List findUserNamesByAge(@Param("age") int age); }
Convert Object Array in Service Layer
public List> getUserNamesByAge(int age) { List users = userRepository.findUserNamesByAge(age); return users.stream() .map(obj -> Map.of("id", obj[0], "name", obj[1])) .collect(Collectors.toList()); }
Expected Response
[ { "id": 1, "name": "John" }, { "id": 2, "name": "Sathish" } ]

Advantage: More flexible, can handle complex queries.


Using DTO (Data Transfer Object) Projection

 Example: Fetching id, name, and age into a DTO


UserDTO.java
public class UserDTO { private Long id; private String name; private int age; public UserDTO(Long id, String name, int age) { this.id = id; this.name = name; this.age = age; } // Getters public Long getId() { return id; } public String getName() { return name; } public int getAge() { return age; } }
Modify Repository to Use DTO
public interface UserRepository extends JpaRepository { @Query("SELECT new com.example.dto.UserDTO(u.id, u.name, u.age) FROM User u WHERE u.age > :age") List findUsersByAge(@Param("age") int age); }
Service Method
public List getUsersByAge(int age) { return userRepository.findUsersByAge(age); }
Expected Response
[ { "id": 1, "name": "John", "age": 30 }, { "id": 2, "name": "Sathish", "age": 28 } ]

Advantage: Works well with custom DTO transformations.


Native SQL Queries with Projection

If you need raw SQL, use @Query(nativeQuery = true).

Modify Repository for Native Query
public interface UserRepository extends JpaRepository { @Query(value = "SELECT id, name FROM users WHERE age > :age", nativeQuery = true) List findUsersByAgeNative(@Param("age") int age); }
Convert Object Array in Service Layer
public List> getUsersByAgeNative(int age) { List users = userRepository.findUsersByAgeNative(age); return users.stream() .map(obj -> Map.of("id", obj[0], "name", obj[1])) .collect(Collectors.toList()); }
Expected Response
[ { "id": 1, "name": "John" }, { "id": 2, "name": "Sathish" } ]

Advantage: Ideal for complex SQL queries with joins, group by, etc.