Gymterview
middle

Что такое проекции и DTO-маппинг?

Проекции позволяют загружать только нужные поля из БД, а не полные сущности. Это оптимизирует производительность и решает проблемы с LAZY-загрузкой и безопасностью (не отдавать лишние данные).

DTO через JPQL-конструктор

Пример
public record UserDto(String name, String email) {}

@Query("SELECT new com.example.UserDto(u.name, u.email) FROM User u WHERE u.id = :id")
Optional<UserDto> findUserDtoById(@Param("id") Long id);
// SQL: SELECT u.name, u.email FROM users u WHERE u.id = ?

Interface-based проекция (Spring Data)

Пример
public interface UserSummary {
    String getName();
    String getEmail();

    @Value("#{target.name + ' <' + target.email + '>'}")
    String getDisplayName(); // вычисляемое поле (SpEL)
}

public interface UserRepository extends JpaRepository<User, Long> {
    List<UserSummary> findByStatus(UserStatus status);
    // Spring Data автоматически загружает только name и email
}

Class-based проекция (DTO класс)

Пример
public record UserDto(String name, String email) {}

List<UserDto> findByStatus(UserStatus status);
// Spring Data маппит результат в DTO автоматически (по именам полей)

Tuple (кортеж) — для ad-hoc запросов

Пример
List<Tuple> results = entityManager.createQuery(
    "SELECT u.name AS name, COUNT(o) AS orderCount " +
    "FROM User u LEFT JOIN u.orders o GROUP BY u.name", Tuple.class)
    .getResultList();

results.forEach(t -> System.out.println(
    t.get("name") + ": " + t.get("orderCount")));

Важное

  • Проекции загружают только нужные столбцы → меньше трафика, памяти, нет LAZY-проблем
  • Interface-based проекции — удобны, но создают прокси (чуть медленнее)
  • Record DTO — оптимальный по производительности вариант
  • Проекции не отслеживаются Persistence Context → нет Dirty Checking

Частые ошибки

  • Загружать полную Entity для read-only отображения — лишний overhead: Dirty Checking, snapshot, L1 Cache
  • Смешивать проекции и Entity — проекция возвращает DTO, не managed Entity; изменения в DTO не попадут в БД
  • Сложные SpEL в interface-проекциях — сложнее для отладки и тестирования

Как используется в 2026

  • DTO-проекции — стандарт для REST API (разделение read/write модели — CQRS-lite)
  • Java Records идеально подходят для DTO — иммутабельные, компактные
  • Spring Data автоматически оптимизирует SELECT при использовании interface/class проекций

На собеседовании: проекции — это способ загружать только нужные поля вместо полной Entity. Назовите три вида: JPQL-конструктор, interface-based, class-based (record). Объясните, почему проекции лучше для REST API: нет Dirty Checking overhead, нет LAZY-проблем, не отдаём лишние данные клиенту.