1. Знайомство з Criteria API
У Hibernate є два способи написання запитів до бази:
- Hibernate Query Language
- Criteria API
З першим ми вже давно познайомилися, настав час дізнатися про Criteria API. Це дуже потужний інструмент, і в якийсь момент він був навіть популярнішим за HQL. Зараз він уже не такий популярний, але для деяких завдань він безумовно буде кращим рішенням, ніж HQL.
У жодному разі не можна вивчати Hibernate і не познайомитися з Criteria API. Давай напишемо невеликий приклад, а потім його розберемо. Скажімо, зробимо запит на всіх співробітників (Employee) із бази. Ось що в нас вийде:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Employee> critQuery = builder.createQuery(Employee.class);
Root&Employee> root = critQuery.from(Employee.class);
critQuery.select(root);
Query<Employee> query = session.createQuery(critQuery);
List<Employee> results = query.getResultList();
Виглядає важкувато. Давай для порівняння запишемо той самий запит на HQL:
String hqlQuery = "від Employee";
Query<Employee> query = session.createQuery(hqlQuery);
List<Employee> results = query.getResultList();
Зверни увагу, що два останні рядки в обох прикладах практично ідентичні: ми створюємо об'єкт Query і за його допомогою отримуємо List. Це натякає на те, що інші рядки роблять щось ідентичне.
Подивися на рядки 3 та 4 першого прикладу:
Root&Employee> root = critQuery.from(Employee.class);
critQuery.select(root);
Давай запишемо їх в один рядок:
critQuery.select(critQuery.from(Employee.class));
Нічого не нагадує? А якщо розфарбувати трохи інакше:
critQuery.select(critQuery.from(Employee.class));
Так, це таке хитре конструювання запиту SELECT FROM.
2. Приклади роботи з Criteria API
Для кращого розуміння я просто наведу кілька прикладів.
Запит 1. Отримати всіх співробітників із зарплатою понад 10 тисяч:
critQuery.select(critQuery.from(Employee.class)).where(builder.gt(root.get("salary"), 10000));
Запит 2. Отримати всіх співробітників із зарплатою менше 50 тисяч:
critQuery.select(critQuery.from(Employee.class)).where(builder.lt(root.get("salary"), 50000));
Запит 3. Отримати всіх працівників, посада яких містить слово "тест":
critQuery.select(critQuery.from(Employee.class)).where(builder.like(root.get("occupation"), "%тест%"));
Запит 4. Отримати всіх співробітників із зарплатою від 10 до 50 тисяч:
critQuery.select(critQuery.from(Employee.class)).where(builder.between(root.get("salary"), 10000, 50000));
Запит 5. Отримати всіх співробітників, у яких ім'я дорівнює null:
critQuery.select(critQuery.from(Employee.class)).where(builder.isNull(root.get("name"))));
Запит 6. Отримати всіх співробітників, у яких ім'я не дорівнює null:
critQuery.select(critQuery.from(Employee.class)).where(builder.isNotNull(root.get("name"))));
Це просто такий хитрий спосіб конструювати запит:
- Спочатку ти отримуєш об'єкт CriteriaBuilder.
- Потім за його допомогою створюєш об'єкт CriteriaQuery.
- Потім починаєш додавати до нього частини за допомогою CriteriaQuery та CriteriaBuilder.
Саме таким чином ти можеш встановити параметри для:
- SELECT
- FROM
- WHERE
Також за допомогою CriteriaBuilder ти можеш конструювати різні умови для WHERE.
3. Просунута робота з Criteria API
За допомогою Criteria API можна сформулювати запит будь-якої складності. І це чудова новина. Наприклад, ти хочеш складну умову для WHERE. Ось як це можна зробити:
Predicate greaterThan = builder.gt(root.get("salary"), 1000);
Predicate testers = builder.like(root.get("occupation"), "тест%");
critQuery.select(critQuery.from(Employee.class)).where(builder.or(greaterThan, testers));
Якщо ти хочеш написати AND замість OR, тобі потрібно поміняти лише останній рядок:
critQuery.select(critQuery.from(Employee.class)).where(builder.and(greaterThan, testers));
Все насправді дуже просто. Давай я наведу таблицю з кількома порівняннями:
SQL | Метод | Повний запис |
---|---|---|
a < b | lt(a, b) | builder.lt(a, b) |
a > b | gt(a, b) | builder.gt(a, b) |
a OR b | or(a, b) | builder.or(a, b) |
a AND b | and(a, b) | builder.and(a, b) |
a LIKE b | like(a, b) | builder.like(a, b) |
a BETWEEN (c, d) | between(a, c, d) | builder.between(a, c, d) |
a IS NULL | isNull(a) | builder.isNull(a) |
a IS NOT NULL | isNotNull(a) | builder.isNotNull(a) |
Все просто, чи не так?
А як нам додати сортування на запит? Дуже просто:
critQuery.select( critQuery.from(Employee.class) );
critQuery.where( builder.and(greaterThan, testers) );
critQuery.orderBy( builder.asc(root.get("salary"), builder.desc(root.get("joinDate") )
Ти просто викликаєш в об'єкта CriteriaQuery метод orderBy() і передаєш у нього потрібні параметри.
>Ось як цей же запит буде виглядати на HQL. Порівняй:
select * from Employee
where (…) and (…)
Order by 'salary' asc, 'joinDate' desc
Тільки потрібно запам'ятати 3 речі:
- Ключові оператори типу SELECT, FROM, WHERE викликаються в об'єкта CriteriaQuery.
- Допоміжні оператори типу AND, OR, DESC викликаються в об'єкта CriteriaBuilder.
- Імена полів беруться через get() у об'єкта Root.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ