В конце этого поста вы найдете исходный код для загрузки.
Что такое критерии? В настоящее время это лучшее решение для создания динамических запросов. Представьте себе страницу, которая позволяет пользователю выполнять несколько типов запросов; Запрашиваемый запрос может быть по имени, по возрасту или с обоими. Посмотрите ниже, как будет выглядеть запрос, если мы объединяем строку:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
EntityManager em = emf.createEntityManager();String hql = "select p from Person p where 1=1 ";if(parameters[0].equals("name")){ hql += " and p.name = '" + values[0] + "'";}if(parameters[1].equals("age")){ hql += " and p.age = " + values[1];}TypedQuery<Person> query = em.createQuery(hql, Person.class);System.out.println(query.getResultList()); |
Обратите внимание, что в приведенном выше коде сделана конкатенация строк; помните, что эта практика плохая и опасная, поскольку она допускает хакерскую атаку «SQL-инъекция». Чтобы избежать этой атаки, мы должны использовать запрос с параметрами:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
EntityManager em = emf.createEntityManager();String hql = "select p from Person p where 1=1 ";if(parameters.contains("name")){ hql += " and p.name = :name";}if(parameters.contains("age")){ hql += " and p.age = :age";}TypedQuery<Person> query = em.createQuery(hql, Person.class);if(parameters.contains("name")){ query.setParameter("name", values[0].toString());}if(parameters.contains("age")){ query.setParameter("age", Integer.valueOf(values[1].toString()));}System.out.println(query.getResultList()); |
Обратите внимание, что проблема SQL-инъекции была решена, но теперь код должен проверить параметры, чтобы добавить его в запрос, а затем передать его значения; для выполнения задачи требуется два «поиска параметров».
У разработчиков Java / Oracle была блестящая идея, когда они создали концепцию Criteria, которая идеально подходит для такой ситуации. Проверьте ниже, как код будет выглядеть с родными критериями JPA:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
EntityManager em = emf.createEntityManager();CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Person> cq = cb.createQuery(Person.class);Root<Person> root = cq.from(Person.class);cq.select(root);if(parameters.contains("name")){ Path<String> name = root.get("name"); cq.where(cb.and(cb.equal(name, values[0])));}if(parameters.contains("age")){ Path<Integer> name = root.get("age"); cq.where(cb.and(cb.equal(name, Integer.valueOf(values[1].toString()))));}TypedQuery<Person> query = em.createQuery(cq);System.out.println(query.getResultList()); |
Можно увидеть, что передать значения параметров проще. Нет необходимости объединять String или проверять значения списка параметров для заполнения значений.
К сожалению, Criteria API является сложным и многословным до крайности. Если вы хотите сделать только «выберите p из Person p», вам нужно создать критерии ниже:
|
1
2
3
4
5
6
7
8
|
EntityManager em = emf.createEntityManager();CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Person> cq = cb.createQuery(Person.class);Root<Person> root = cq.from(Person.class);cq.select(root);TypedQuery<Person> query = em.createQuery(cq);System.out.println(query.getResultList()); |
Это много кода, чтобы сделать что-то так легко, список всех людей из таблицы.
Чтобы избежать всего этого многословия, был создан проект с открытым исходным кодом EasyCriteria. Если разработчик использует EasyCriteria, запрос выше будет выглядеть следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
EntityManager em = emf.createEntityManager();EasyCriteria<Person> easyCriteria = EasyCriteriaFactory.createQueryCriteria(em, Person.class);if(parameters.contains("name")){ easyCriteria.whereEquals("name", values[0]);}if(parameters.contains("age")){ easyCriteria.whereEquals("age", values[1]);}System.out.println(easyCriteria.getResultList()); |
Обратите внимание, что все детали JPA исчезли. Теперь можно иметь чистый код, проще создавать динамические запросы. О вышеприведенном коде стоит поговорить:
- Строка 2: экземпляр EasyCriteria создается с помощью «фабрики». Эта фабрика существует для абстракции всех необходимых крутых путей для создания объекта типа EasyCriteriaImp. В будущих версиях будут добавлены новые типы EasyCriteria, например, «Tuple».
- Строки 5 и 9: параметры легче передать. Чтобы передать параметры для сравнения значений («имя =: имя»), просто используйте метод equals, который принимает в качестве первого параметра имя атрибута; вторым параметром будет значение, которое будет равно.
- Строка 12: для запуска запроса нет необходимости использовать интерфейс запроса. EasyCriteria сама берет на себя эту ответственность. Можно извлечь результат запроса через EasyCriteria. Для получения результата запроса доступны два метода: EasyCriteria.getSingleResult (), EasyCriteria.getResultList ().
На веб-странице EasyCriteria доступно несколько примеров кода и методы, которые можно использовать. Другим преимуществом EasyCriteria является возможность «связать» все методы:
|
1
|
easyCriteria.whereEquals("name", values[0]).whereEquals("age", values[1]).getResultList(); |
Это легковесная библиотека, потому что единственная зависимость — это JPA, который понадобится системе. Внимание: ваше приложение должно иметь запущенную реализацию JPA.
Эта библиотека была разработана с помощью JUnit и протестирована с Hibernate, OpenJPA и EclipseLink. JUnit также использует платформу Cobertura для проверки, покрыты ли все строки кода (или большая их часть) тестами, поэтому мы получили 100% покрытия.
EasyCriteria все еще находится в бета-версии, но команда разработчиков уже запланировала некоторые выпуски и функции.
Другое преимущество EasyCriteria заключается в том, что ваш программный код больше не «связан» с любым видом реализации JPA. Сегодня Hibernate имеет хороший инструмент критериев, но ваш код должен оставаться «привязанным» к нему. С EasyCriteria вы сможете использовать любую реализацию JPA. Доказательством этой развязанной библиотеки является то, что EasyCriteria была протестирована с 3 реализациями, процитированными ранее.
У EasyCriteria есть методы: в пустых и других. Разработчик сможет сделать объединение (просто простое объединение без параметра), отдельное или даже упорядоченное всеми с помощью Criteria.
Здесь вы найдете EasyCriteria для загрузки и доступ ко всей документации.
Нажмите здесь, чтобы загрузить исходный код этого поста.
Я надеюсь, что этот пост / инструмент может помочь вам.
Ссылка: EasyCriteria — простой способ использования критериев JPA от нашего партнера по JCG Хеберта Коэльо в блоге uaiHebert .
