Clean • Professional
In real-world applications, fetching entire entities is often unnecessary and inefficient. Most use cases—such as REST APIs, dashboards, reports, and list views—require only a subset of fields.
Fetching full entities along with their relationships can lead to:
DTO Projections in Spring Data JPA solve this by allowing you to fetch only the required columns directly from the database and map them into DTOs (Data Transfer Objects).
A DTO Projection retrieves partial data from the database and maps it directly into:
Instead of returning managed JPA entities, repository methods return DTOs.
LazyInitializationException👉 DTO projections are faster, safer, and cleaner than entities when updates are not required.
Spring Data JPA supports three main projection types:

Spring Data JPA automatically creates a proxy implementation and fetches only the fields declared in the interface.
Projection Interface
publicinterfaceUserSummary {
LonggetId();
StringgetName();
StringgetEmail();
}
Repository
publicinterfaceUserRepositoryextendsJpaRepository<User, Long> {
List<UserSummary>findByActiveTrue();
}
Uses JPQL’s new keyword to map query results into a DTO.
DTO Class
publicclassUserDTO {
private Long id;
private String name;
private String email;
publicUserDTO(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
}
Repository
@Query("""
SELECT new com.example.dto.UserDTO(u.id, u.name, u.email)
FROM User u
WHERE u.active = true
""")
List<UserDTO>findActiveUsers();
Useful when the same query must return different views of data.
Repository
publicinterfaceUserRepositoryextendsJpaRepository<User, Long> {
<T> List<T>findByActiveTrue(Class<T> type);
}
Usage
List<UserSummary> summaries =
userRepository.findByActiveTrue(UserSummary.class);
List<UserDTO> dtos =
userRepository.findByActiveTrue(UserDTO.class);
DTO projections can include nested objects using interfaces.
publicinterfaceOrderView {
LonggetId();
UserInfogetUser();
interfaceUserInfo {
StringgetName();
StringgetEmail();
}
}
List<OrderView>findAll();
⚠️ Overusing nested projections may still trigger extra joins or queries.
| Feature | DTO Projection | Entity Fetching |
|---|---|---|
| Data fetched | Only selected fields required for the use case are fetched from the database | The complete entity with all mapped fields is fetched |
| Performance | Faster because less data is retrieved and processed | Slower because the full entity is loaded |
| Memory usage | Lower memory consumption since only required fields are stored | Higher memory usage because full entities are kept in memory |
| Change tracking | Changes are not tracked because DTOs are not managed by JPA | Changes are tracked automatically by the JPA persistence context |
| Lazy loading | Lazy loading is not applicable because DTOs are not entities | Lazy loading is supported for entity relationships |
| N+1 query risk | Very low risk because data is fetched explicitly in queries | Possible if lazy associations are accessed without proper fetch strategy |
| Updates allowed | Read-only and should not be used for update operations | Supports create, update, and delete operations |
| Transaction requirement | Usually not required for simple read-only queries | Required, especially when using lazy-loaded associations |
| API safety | Safe for APIs because internal entity structure is hidden | Risky for APIs because entities may expose unwanted data |
| Best for APIs | Highly recommended for REST APIs and external clients | Not recommended for direct API exposure |
| Best use case | Read-only views, reports, dashboards, and API responses | Business logic, data manipulation, and persistence operations |
Key Takeaway (Easy Rule)
DTO Projection → When you only read data
Entity Fetching → When you modify data
@EntityGraph| Feature | DTO Projection | @EntityGraph |
|---|---|---|
| What it returns | Returns a Data Transfer Object containing only selected fields | Returns a fully managed JPA entity |
| Primary use case | Best for read-only data such as API responses, dashboards, and reports | Best for business logic where entity behavior and updates are required |
| Fetch control | Controls exactly which columns are selected from the database | Controls which related entities are fetched eagerly |
| Updates allowed | Not allowed because DTOs are not managed by JPA | Allowed because entities are managed by the persistence context |
| Performance | Very high because only required fields are fetched | Good, but slower than DTOs because full entities are loaded |
| Memory usage | Low because partial data is stored | Higher because full entities and relationships are kept in memory |
| Lazy loading behavior | Not applicable because DTOs do not support lazy loading | Fully supported for non-selected associations |
| Risk of N+1 problem | Very low because data is fetched explicitly | Possible if associations are not included in the entity graph |
| Best for REST APIs | Highly recommended and safe | Not recommended for direct exposure |
| Complexity | Simple and lightweight | More complex due to entity management |
Controller
|
|--> Repository
|
|--> DTO Projection
|
|--> Only required columns
@EntityGraph (not a replacement)