Ответ
JPA Criteria API — это типобезопасный, объектно-ориентированный способ динамического построения запросов к базе данных в Java. Вместо строк JPQL/SQL запрос конструируется вызовом методов Java.
Ключевые преимущества:
- Типобезопасность: Ошибки (например, опечатки в именах полей) обнаруживаются на этапе компиляции, а не в runtime.
- Защита от SQL-инъекций: Поскольку запрос строится через API, риск инъекций практически исключен.
- Динамические запросы: Идеально подходит для построения запросов с переменным набором условий (например, в сложных фильтрах).
- Рефакторинг: IDE может автоматически переименовывать поля сущностей, используемые в запросах.
Основные компоненты:
CriteriaBuilder— фабрика для создания всех частей запроса (where,select,orderBy).CriteriaQuery<T>— объект, представляющий запрос. Определяет тип результата (T).Root<T>— корневой элемент запроса, представляет сущность, от которой строится запрос.Predicate— условие для предложенияWHERE. Условия можно комбинировать (and,or).
Пример: Поиск сотрудников с зарплатой выше заданной и сортировкой.
EntityManager em = ... // получение EntityManager
CriteriaBuilder cb = em.getCriteriaBuilder();
// 1. Создаем запрос, который вернет список Employee
CriteriaQuery<Employee> query = cb.createQuery(Employee.class);
// 2. Определяем корневую сущность запроса (FROM Employee)
Root<Employee> employee = query.from(Employee.class);
// 3. Строим предикат для условия WHERE (salary > minSalary)
ParameterExpression<Double> minSalaryParam = cb.parameter(Double.class);
Predicate salaryCondition = cb.gt(employee.get("salary"), minSalaryParam);
// 4. Собираем запрос
query.select(employee)
.where(salaryCondition)
.orderBy(cb.desc(employee.get("salary"))); // ORDER BY salary DESC
// 5. Создаем TypedQuery, устанавливаем параметр и выполняем
TypedQuery<Employee> typedQuery = em.createQuery(query);
typedQuery.setParameter(minSalaryParam, 100000.0);
List<Employee> resultList = typedQuery.getResultList();
Сложный пример с динамическими условиями:
List<Predicate> predicates = new ArrayList<>();
if (departmentName != null) {
predicates.add(cb.equal(employee.get("department").get("name"), departmentName));
}
if (minExperience != null) {
predicates.add(cb.ge(employee.get("experienceYears"), minExperience));
}
// Объединяем все условия через AND
query.where(cb.and(predicates.toArray(new Predicate[0])));
Когда использовать: Выбирайте Criteria API для сложных, изменчивых запросов, формируемых в runtime. Для простых статических запросов предпочтительнее использовать именованные запросы (@NamedQuery) или строки JPQL.