Логотип Workflow

Article

Updated at:

Jpql

Этап 6 - JPQL: запросы к entities вместо таблиц

JPQL делает запрос к entity model, а SQL делает запрос к database schema. Он похож на SQL, но работает с entity classes и entity fields, а не напрямую с table names и column names. SQL говорит select * from users; JPQL говорит SELECT u FROM User u. Hibernate переводит JPQL в SQL для конкретной базы данных.

JPQL compared to SQL

Синтаксис JPQL

Базовый query выбирает из entity:

@Query("SELECT u FROM User u")
List<User> findAllUsers();

User - имя entity class, а u - alias. Conditions используют имена entity fields:

@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);

JPQL поддерживает WHERE, ORDER BY, GROUP BY, aggregate functions и joins через entity relationships. Join идет по object references, а не по raw foreign key columns:

@Query("SELECT o FROM Order o JOIN o.user u WHERE u.email = :email")
List<Order> findOrdersByUserEmail(@Param("email") String email);

Параметры

Named parameters используют :name и обычно понятнее positional parameters. Positional parameters используют ?1, ?2 и так далее. Named parameters лучше переживают refactoring, потому что смысл параметра виден прямо в query.

Потребность queryБолее удачный JPQL styleПочему это объясняет намерение
Отфильтровать по одному business valueWHERE u.email = :emailИмя параметра показывает, что значение является email, а не просто первым аргументом.
Отфильтровать по нескольким значениямWHERE p.price BETWEEN :min AND :maxNamed parameters не дают перепутать два значения одного Java type.
Сделать join через relationshipJOIN o.user uJPQL идет по entity relation вместо ручного orders.user_id = users.id.
Вернуть list screenSELECT new ...ProductSummary(...)DTO projection грузит только поля, реально нужные response.

DTO projection

Иногда API нужны только несколько полей. Загружать полные entities может быть расточительно, особенно если есть relationships. JPQL может создавать DTO projections:

@Query("""
    SELECT new com.example.UserSummary(u.id, u.email, u.name)
    FROM User u
    WHERE u.active = true
    ORDER BY u.name
""")
List<UserSummary> findActiveUserSummaries();

DTO projection полезен для read-only screens, list endpoints и reporting. Он уменьшает объем загружаемых данных и помогает избежать случайного lazy loading. Компромисс в том, что DTO constructor и query должны совпадать.

JPQL или derived queries

Spring Data умеет создавать queries по именам методов, например findByEmail или findByNameContainingIgnoreCase. Это отлично для простых условий. JPQL лучше, когда нужны joins, grouping, custom sorting logic, projections или условие, которое сделает имя метода нечитаемым.

Практика

Добавь queries для поиска пользователей по email, фильтрации товаров по price range и availability, а также сортировки товаров по name. Затем добавь DTO projection, который возвращает только product id, name и price. Сравни generated SQL через SQL logging. Цель не в заучивании JPQL syntax, а в понимании, что JPQL описывает операции над entity model.

Чек-лист понимания

  • Могу объяснить, чем JPQL отличается от SQL.
  • Знаю, что JPQL использует имена entities и fields.
  • Могу использовать @Query с named parameters.
  • Понимаю, когда полезен DTO projection.
  • Могу выбрать между derived query methods и JPQL.

Авторизуйтесь чтоб пройти тесты

Practice

Интерактивная практика

Выполните задания и сразу проверьте ответ.