В конце этого поста вы найдете исходный код для загрузки.
Что такое критерии? В настоящее время это лучшее решение для создания динамических запросов. Представьте себе страницу, которая позволяет пользователю выполнять несколько типов запросов; Запрашиваемый запрос может быть по имени, по возрасту или с обоими. Посмотрите ниже, как будет выглядеть запрос, если мы объединяем строку:
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 .