Spring Boot JPA Projection (Fetching Specific Columns)
~1 min read
·
Spring Boot
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
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Define a Projection Interface
public interface UserProjection {
Long getId ();
String getName ();
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Modify Repository to Use Projection
public interface UserRepository extends JpaRepository <User , Long > {
// Fetch only id and name
List <UserProjection > findByAgeGreaterThan (int age );
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Fetch Data in Service Layer
@Service
public class UserService {
@Autowired
private UserRepository userRepository ;
public List <UserProjection > getUsersByAge (int age ) {
return userRepository.findByAgeGreaterThan(age);
}
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Response JSON (Example)
[
{ "id" : 1 , "name" : "John" },
{ "id" : 2 , "name" : "Sathish" }
]
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
✅ 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 <User , Long > {
@Query("SELECT u.id, u.name FROM User u WHERE u.age > :age" )
List <Object []> findUserNamesByAge (@Param("age" ) int age );
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Convert Object Array in Service Layer
public List <Map <String , Object >> getUserNamesByAge (int age ) {
List <Object []> users = userRepository.findUserNamesByAge(age);
return users.stream()
.map(obj -> Map.of("id" , obj[0 ], "name" , obj[1 ]))
.collect(Collectors.toList());
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Expected Response
[
{ "id" : 1 , "name" : "John" },
{ "id" : 2 , "name" : "Sathish" }
]
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
✅ 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; }
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Modify Repository to Use DTO
public interface UserRepository extends JpaRepository <User , Long > {
@Query("SELECT new com.example.dto.UserDTO(u.id, u.name, u.age) FROM User u WHERE u.age > :age" )
List <UserDTO > findUsersByAge (@Param("age" ) int age );
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Service Method
public List <UserDTO > getUsersByAge (int age ) {
return userRepository.findUsersByAge(age);
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Expected Response
[
{ "id" : 1 , "name" : "John" , "age" : 30 },
{ "id" : 2 , "name" : "Sathish" , "age" : 28 }
]
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
✅ 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 <User , Long > {
@Query(value = "SELECT id, name FROM users WHERE age > :age" , nativeQuery = true )
List <Object []> findUsersByAgeNative (@Param("age" ) int age );
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Convert Object Array in Service Layer
public List <Map <String , Object >> getUsersByAgeNative (int age ) {
List <Object []> users = userRepository.findUsersByAgeNative(age);
return users.stream()
.map(obj -> Map.of("id" , obj[0 ], "name" , obj[1 ]))
.collect(Collectors.toList());
}
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
Expected Response
[
{ "id" : 1 , "name" : "John" },
{ "id" : 2 , "name" : "Sathish" }
]
show = true, 3000)" class="absolute top-[10px] right-[10px] inline-flex items-center justify-center gap-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-smooth h-9 rounded-md px-3 cursor-pointer bg-white/80 border border-border">
✅ Advantage: Ideal for complex SQL queries with joins, group by , etc.