Какие способы написания собственных запросов существуют в JPA?

«Какие способы написания собственных запросов существуют в JPA?» — вопрос из категории Hibernate, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, JPA предоставляет несколько механизмов для написания запросов:

1. JPQL (Java Persistence Query Language)

Объектно-ориентированный язык запросов, похожий на SQL, но работающий с сущностями.

TypedQuery<User> query = em.createQuery(
    "SELECT u FROM User u WHERE u.age > :minAge", User.class
);
query.setParameter("minAge", 18);
List<User> users = query.getResultList();

2. Нативные SQL-запросы (Native Queries)

Используются для сложных запросов или специфичных для СУБД функций.

Query query = em.createNativeQuery(
    "SELECT * FROM users WHERE registration_date > ?", User.class
);
query.setParameter(1, startDate);
List<User> users = query.getResultList();

3. Criteria API

Типобезопасный и динамический способ построения запросов через Java API.

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> user = cq.from(User.class);
cq.select(user).where(cb.gt(user.get("age"), 18));
List<User> users = em.createQuery(cq).getResultList();

4. Именованные запросы (Named Queries)

Предопределенные запросы, объявляемые с помощью аннотации @NamedQuery прямо в классе сущности.

@Entity
@NamedQuery(name = "User.findByStatus",
            query = "SELECT u FROM User u WHERE u.status = :status")
public class User { ... }
// Использование
List<User> users = em.createNamedQuery("User.findByStatus", User.class)
                     .setParameter("status", "ACTIVE")
                     .getResultList();

Выбор подхода зависит от сложности запроса, требований к производительности, необходимости динамического построения и предпочтений команды.