Що таке projection в JPA
Projection — завантаження тільки потрібних полів сутності замість всього об'єкта. Це значно покращує продуктивність, зменшує обсяг даних в пам'яті та усуває необхідність dirty c...
Огляд
Projection — завантаження тільки потрібних полів сутності замість всього об’єкта. Це значно покращує продуктивність, зменшує обсяг даних в пам’яті та усуває необхідність dirty checking для read-only операцій.
🟢 Junior Level
Що таке projection
Projection — завантаження частини полів замість всієї сутності.
// Вся сутність — всі поля
SELECT u FROM User u
// Projection — тільки потрібні поля
SELECT u.name, u.email FROM User u
Навіщо використовувати
- Менше даних з БД → швидший запит
- Менше даних в пам’яті → економія
- Немає dirty checking → менше overhead
- Контрольований контракт API
Простий приклад
// DTO клас
public record UserDto(String name, String email) {}
// JPQL з конструктором
@Query("SELECT new com.example.UserDto(u.name, u.email) FROM User u")
List<UserDto> findUserDtos();
🟡 Middle Level
Типи projection
1. Array projection
@Query("SELECT u.name, u.email FROM User u")
List<Object[]> findNamesAndEmails();
Мінуси: type-unsafe, незручно
2. DTO projection (constructor expression)
public record UserDto(String name, String email) {}
@Query("SELECT new com.example.UserDto(u.name, u.email) FROM User u")
List<UserDto> findUserDtos();
Плюси: type-safe, зручно
3. Interface-based (Spring Data)
interface UserNameOnly {
String getName();
String getEmail();
}
List<UserNameOnly> findBy();
Плюси: Spring створює proxy через інтерфейс
Типові помилки
// ❌ Без повного імені класу
@Query("SELECT new UserDto(u.name, u.email) FROM User u") // ❌
// ✅ З повним іменем
@Query("SELECT new com.example.UserDto(u.name, u.email) FROM User u") // ✅
// ❌ Неправильний порядок аргументів
public record UserDto(String email, String name) {} // email, name
@Query("SELECT new com.example.UserDto(u.name, u.email) FROM User u") // ❌
🔴 Senior Level
Performance порівняння
Full entity:
- SELECT * → завантаження всіх полів
- Dirty checking overhead
- L1 cache storage
Projection:
- SELECT specific columns
- Немає dirty checking
- Менше пам'яті
Projection значно економить пам'ять (завантажуються тільки потрібні колонки)
і прискорює запит (менше даних по мережі).
Коли використовувати projection
✅ Projection для:
- Read-only операцій
- API відповідей
- Списків/таблиць
- Агрегації та статистики
- Великих наборів даних
❌ Повна сутність для:
- CRUD операцій
- Коли потрібні всі поля
- Коли потрібен dirty checking
Best Practices
✅ DTO projection для read-only
✅ Interface-based для гнучкості
✅ Class-based (record) для type-safety
✅ Повне ім'я класу в JPQL
✅ Правильний порядок аргументів
❌ Array projection (type-unsafe)
❌ Full entity для read-only
🎯 Шпаргалка для співбесіди
Обов’язково знати:
- Projection — завантаження тільки потрібних полів замість всієї сутності
- 4 типи: Array (type-unsafe), DTO constructor (type-safe), Interface-based (Spring), Class-based (Spring)
- Переваги: менше даних з БД, немає dirty checking overhead, контрольований API контракт
- DTO projection вимагає повне ім’я класу: new com.example.UserDto(…)
- Для read-only/API — projection, для CRUD — повні сутності
Пов’язані теми:
- [[26. Що таке JPQL і чим він відрізняється від SQL]]
- [[27. Що таке Criteria API і коли його використовувати]]
- [[25. Як уникнути нескінченної рекурсії при серіалізації Entity]]
- [[4. Що таке LazyInitializationException і як її уникнути]]