Обычно я вижу, что некоторые люди задают вопросы о Queries с JPA; Обычно для ответа на такие вопросы предоставляется несколько ссылок, пытаясь найти решение вопроса.
До сегодняшнего дня я не мог найти пост в блоге, в котором собрана хорошая тема о запросах с JPA, советы по производительности / использованию, исходный код для загрузки …
Сегодня мы увидим:
- Классы моделей и класс, который будет генерировать данные базы данных
 - Найти метод; Используйте метод getReference для повышения производительности, отображая параметры запроса в консоли с помощью log4j.
 - JPQL: запросы с простыми параметрами или объектами, объединениями, упорядочением по, перемещением по связям
 - JPQL: Функции: AVG, COUNT, MAX, MIN, TRIM, SUM, UPPER, LOWER, MOD, LENGHT, SQRT; Использование HAVING, GROUP BY
 - JPQL: Условия фильтрации: LIKE, IN, DISTINCT, EMPTY, BETWEEN, NULL, MEMBER OF, EXISTS (подзапросы), ANY, ALL, SOME, CONCAT, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, LOCATE, SIZE, SUBST
 - JPA: NamedQuery, запросы с датами, предупреждения о методе getSingleResult
 - JPA: NativeQuery, NamedNativeQuery
 - JPA: сложные собственные запросы
 - JPA: оптимизация запросов с EJB
 - JPA: нумерация страниц
 - JPA: База данных Советы
 - JPA: создание объекта из запроса
 - JPQL: массовое обновление и удаление
 - JPA: критерии
 
Вы увидите, что в каждом главном классе мы будем вызывать метод « CodeGenerator.generateData () ». Этот метод класса только создает данные в базе данных; с этими данными наши запросы найдут правильные результаты.
На последней странице этого поста вы найдете ссылку для скачивания исходного кода этого поста.
В этом посте мы будем использовать JPA 2.0 с Hibernate в качестве провайдера. База данных будет HSQLDB и будет прикреплена к этому проекту. Вы можете скачать исходный код и запустить проект без необходимости какой-либо дополнительной настройки. Мы не будем говорить о том, как настроить HSQLDB, потому что этот пост посвящен тому, как запрашивать данные базы данных.
Этот пост не будет использовать лучшие практики разработки в некоторых моментах. Основное внимание в этом посте будет уделено отображению работы запросов JPA.
Классы моделей и класс, который будет генерировать данные базы данных
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
 | 
package com.model;import java.util.ArrayList;import java.util.List;import javax.persistence.CascadeType;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.OneToMany;import javax.persistence.OneToOne;@Entitypublic class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String name; private int age; public Person() { } public Person(String name, int age) {  this.name = name;  this.age = age; } @OneToMany(mappedBy = 'person', cascade = CascadeType.ALL) private List<Dog> dogs; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name='address_id') private Address address; public int getId() {  return id; } public void setId(int id) {  this.id = id; } public String getName() {  return name; } public void setName(String name) {  this.name = name; } public int getAge() {  return age; } public void setAge(int age) {  this.age = age; } public List<Dog> getDogs() {  if (dogs == null) {   dogs = new ArrayList<Dog>();  }  return dogs; } public void setDogs(List<Dog> dogs) {  this.dogs = dogs; } public Address getAddress() {  return address; } public void setAddress(Address address) {  this.address = address; } @Override public int hashCode() {  return getId(); } @Override public boolean equals(Object obj) {  if (obj instanceof Person) {   Person person = (Person) obj;   return person.getId() == getId();  }  return false; }} | 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
 | 
package com.model;import java.util.Date;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.ManyToOne;import javax.persistence.Temporal;import javax.persistence.TemporalType;@Entitypublic class Dog { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String name; private double weight; @Temporal(TemporalType.TIMESTAMP) private Date dateOfBirth; public Dog() { } public Dog(String name, double weight, Date dateOfBirth) {  this.name = name;  this.weight = weight;  this.dateOfBirth = dateOfBirth; } public static void main(String[] args) {  System.out.println(new Date()); } @ManyToOne private Person person; public int getId() {  return id; } public void setId(int id) {  this.id = id; } public String getName() {  return name; } public void setName(String name) {  this.name = name; } public double getWeight() {  return weight; } public void setWeight(double weight) {  this.weight = weight; } public Date getDateOfBirth() {  return dateOfBirth; } public void setDateOfBirth(Date dateOfBirth) {  this.dateOfBirth = dateOfBirth; } public Person getPerson() {  return person; } public void setPerson(Person person) {  this.person = person; } @Override public int hashCode() {  return getId(); } @Override public boolean equals(Object obj) {  if (obj instanceof Dog) {   Dog dog = (Dog) obj;   return dog.getId() == getId();  }  return false; }} | 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
 | 
package com.model;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;@Entitypublic class Address { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String streetName; private int houseNumber; public Address() { } public Address(String streetName, int houseNumber) {  this.streetName = streetName;  this.houseNumber = houseNumber; } public int getId() {  return id; } public void setId(int id) {  this.id = id; } public String getStreetName() {  return streetName; } public void setStreetName(String streetName) {  this.streetName = streetName; } public int getHouseNumber() {  return houseNumber; } public void setHouseNumber(int houseNumber) {  this.houseNumber = houseNumber; } @Override public int hashCode() {  return getId(); } @Override public boolean equals(Object obj) {  if (obj instanceof Address) {   Address address = (Address) obj;   return address.getId() == getId();  }  return false; }} | 
Мы получили несколько базовых классов с однонаправленными и двунаправленными отношениями. Эти отношения помогут нам манипулировать всеми типами запросов, которые мы будем выполнять.
Для генерации данных базы данных у нас есть класс ниже:
| 
 001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
041 
042 
043 
044 
045 
046 
047 
048 
049 
050 
051 
052 
053 
054 
055 
056 
057 
058 
059 
060 
061 
062 
063 
064 
065 
066 
067 
068 
069 
070 
071 
072 
073 
074 
075 
076 
077 
078 
079 
080 
081 
082 
083 
084 
085 
086 
087 
088 
089 
090 
091 
092 
093 
094 
095 
096 
097 
098 
099 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
 | 
package com.main;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import javax.persistence.EntityManager;import javax.persistence.EntityManagerFactory;import javax.persistence.Persistence;import com.model.Address;import com.model.Dog;import com.model.Person;public class CodeGenerator { private static EntityManagerFactory emf; private static EntityManager em; public static final String PERSON01_NAME = 'John'; public static final String PERSON02_NAME = 'Mary'; public static final String PERSON03_NAME = 'Anna'; public static final String PERSON04_NAME = 'Joseph'; public static final String PERSON05_NAME = 'Mark'; public static final String PERSON06_NAME = 'I will not have any relationship'; public static void startConnection() {  emf = Persistence.createEntityManagerFactory('JpaQuery');  em = emf.createEntityManager();  em.getTransaction().begin(); } public static void closeConnection() {  em.getTransaction().commit();  emf.close(); } public static void generateData() {  int year = 1995;  int month = 1;  int day = 10;  Dog dog01 = new Dog('Yellow', 3.5d, createNewDate(day, month, year));  Dog dog02 = new Dog('Brown', 8.5d, createNewDate(++day, ++month, ++year));  Dog dog03 = new Dog('Dark', 15.5d, createNewDate(++day, ++month, ++year));  Dog dog04 = new Dog('Kaka', 4.3d, createNewDate(++day, ++month, ++year));  Dog dog05 = new Dog('Pepe', 8.2d, createNewDate(++day, ++month, ++year));  Dog dog06 = new Dog('Casillas', 6.1d, createNewDate(++day, ++month, ++year));  Dog dog07 = new Dog('Fish', 6.7d, createNewDate(++day, ++month, ++year));  Dog dog08 = new Dog('Lion', 3.1d, createNewDate(++day, ++month, ++year));  Dog dog09 = new Dog('Cat', 5.5d, createNewDate(++day, ++month, ++year));  Dog dog10 = new Dog('Java', 21.7d, createNewDate(++day, ++month, ++year));  Dog dog11 = new Dog('JSF', 23.65d, createNewDate(++day, ++month, ++year));  Dog dog12 = new Dog('VRaptor', 24.0d, createNewDate(++day, ++month, ++year));  Dog dog13 = new Dog('Ferrari', 3.7d, createNewDate(++day, ++month, ++year));  Dog dog14 = new Dog('Porshe', 1.33d, createNewDate(++day, ++month, ++year));  Dog dog15 = new Dog('Bike', 4.44d, createNewDate(++day, ++month, ++year));  Dog dog16 = new Dog('Rambo', 5.44d, createNewDate(++day, ++month, 2015));  Dog dog17 = new Dog('Terminator', 3.88d, createNewDate(++day, ++month, 2016));  Dog dog18 = new Dog('John McClan', 3.88d, createNewDate(++day, ++month, 2016));  Person person01 = new Person(PERSON01_NAME, 33);  person01.getDogs().add(dog01);  person01.getDogs().add(dog02);  person01.getDogs().add(dog03);  person01.setAddress(new Address('Street A', 30));  dog01.setPerson(person01);  dog02.setPerson(person01);  dog03.setPerson(person01);  Person person02 = new Person(PERSON02_NAME, 27);  person02.getDogs().add(dog04);  person02.getDogs().add(dog05);  person02.getDogs().add(dog06);  person02.setAddress(new Address('Street B', 60));  dog04.setPerson(person02);  dog05.setPerson(person02);  dog06.setPerson(person02);  Person person03 = new Person(PERSON03_NAME, 7);  person03.getDogs().add(dog07);  person03.getDogs().add(dog08);  person03.getDogs().add(dog09);  person03.setAddress(new Address('Street B', 90));  dog07.setPerson(person03);  dog08.setPerson(person03);  dog09.setPerson(person03);  Person person04 = new Person(PERSON04_NAME, 43);  person04.getDogs().add(dog10);  person04.getDogs().add(dog11);  person04.getDogs().add(dog12);  person04.setAddress(new Address('Street C', 120));  dog10.setPerson(person04);  dog11.setPerson(person04);  dog12.setPerson(person04);  Person person05 = new Person(PERSON05_NAME, 70);  person05.getDogs().add(dog13);  person05.getDogs().add(dog14);  person05.getDogs().add(dog15);  person05.getDogs().add(dog16);  person05.setAddress(new Address('Street D', 150));  dog13.setPerson(person05);  dog14.setPerson(person05);  dog15.setPerson(person05);  dog16.setPerson(person05);  Person person06 = new Person(PERSON06_NAME, 45);  em.persist(person01);  em.persist(person02);  em.persist(person03);  em.persist(person04);  em.persist(person05);  em.persist(person06);  em.persist(dog17);  em.persist(dog18);  em.flush(); } private static Date createNewDate(int day, int month, int year) {  SimpleDateFormat formatter = new SimpleDateFormat('dd/MM/yyyy');  try {   return formatter.parse('' + day + '/' + month + '/' + year);  } catch (ParseException e) {   e.printStackTrace();   return null;  } } public static EntityManager getEntityManager() {  return em; }} | 
Найти метод; Используйте метод getReference для повышения производительности, отображая параметры запроса в консоли с помощью log4j.
Метод find обычно вызывается до того, как мы выполним некоторые изменения в базе данных, такие как обновление какого-либо атрибута объекта, отношения или удаление.
Ниже вы найдете коды, которые используют метод поиска:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
 | 
package com.main;import javax.persistence.EntityManager;import com.model.Address;import com.model.Person;public class Page03 { public static void main(String[] args) {  CodeGenerator.startConnection();  CodeGenerator.generateData();  EntityManager em = CodeGenerator.getEntityManager();  Person person = em.find(Person.class, 1);  int addressId = 2;  // usually we send an id or a detached object from the view  setAddressToOtherPerson(em, person, addressId);  int personId = 4;  // usually we send an id or a detached object from the view  deletePerson(em, personId);  CodeGenerator.closeConnection(); } private static void setAddressToOtherPerson(EntityManager em, Person person, int addressId) {  Address address = em.find(Address.class, addressId);  person.setAddress(address);  em.merge(person);  em.flush(); } private static void deletePerson(EntityManager em, int personId) {  Person savedPerson = em.find(Person.class, personId);  em.remove(savedPerson);  em.flush(); }} | 
Обратите внимание, что методы « setAddressToOtherPerson » и « deletePerson » используют метод find только для обновления ссылки или для удаления объекта.
Метод find () имеет оптимизированную функцию запроса, которая будет искать объект в контексте постоянства, если он не найдет объект, он запросит базу данных для получения данных. Если вы получили отношение, аннотированное с помощью EAGER (например: « @OneToMany (fetch = FetchType.EAGER) »), метод find доставит эти объекты из базы данных. Обратите внимание, что нет необходимости извлекать все эти данные из базы данных для простых задач, таких как удаление обновления ссылки.
EntityManager имеет специальный метод, который помогает с этими простыми задачами. EntityManager выполнит простой запрос типа « выберите идентификатор из Person p, где p.id =: personId ». У нас будет быстрый и меньший запрос.
Ниже вы можете увидеть, как мы будем использовать getReference:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
 | 
package com.main;import javax.persistence.EntityManager;import com.model.Address;import com.model.Person;public class Page03 { public static void main(String[] args) {  CodeGenerator.startConnection();  CodeGenerator.generateData();  EntityManager em = CodeGenerator.getEntityManager();  Person person = em.find(Person.class, 1);  int addressId = 2;  // usually we send an id or a detached object from the view  setAddressToOtherPerson(em, person, addressId);  int personId = 4;  // usually we send an id or a detached object from the view  deletePerson(em, personId);  CodeGenerator.closeConnection(); } private static void setAddressToOtherPerson(EntityManager em, Person person, int addressId) {  Address address = em.getReference(Address.class, addressId);  person.setAddress(address);  em.merge(person);  em.flush();  System.out.println('Merged'); } private static void deletePerson(EntityManager em, int personId) {  // usually is find or merge  Person savedPerson = em.getReference(Person.class, personId);  em.remove(savedPerson);  em.flush();  System.out.println('Deleted'); }} | 
С помощью метода « getReference » вы будете запрашивать только идентификатор объекта, вы сэкономите часть трафика базы данных.
Ниже вы найдете конфигурацию lo4j.properties, необходимую для отображения параметров запросов JPA в консоли. Обычно, когда мы вызываем запрос, используя Hibernate, Hibernate отформатирует запрос с «?» вместо использования реальной стоимости. С кодом ниже вы сможете увидеть параметры запроса:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
 | 
# Direct log messages to stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target=System.outlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n# Root logger optionlog4j.rootLogger=ERROR, stdout# Hibernate logging options (INFO only shows startup messages)log4j.logger.org.hibernate=ERROR# Log JDBC bind parameter runtime argumentslog4j.logger.org.hibernate.type=TRACE | 
Если вы хотите деактивировать журнал, вам нужно просто закомментировать последнюю строку lo4j.properties с символом # и установить для конфигурации show_log в файле «persistence.xml» значение false.
JPQL: запросы с простыми параметрами или объектами, объединениями, упорядочением по, перемещением по связям
Для выполнения базового запроса вам просто нужно выполнить команду, подобную этой: «выберите d из Dog d». Одна вещь, которую вы всегда должны помнить: для выполнения такого запроса мы используем JPQL, а не обычный SQL .
Преимущество использования JPQL состоит в том, что он очень похож на SQL и является переносимым. Вы можете использовать один и тот же запрос в каждой базе данных без проблем.
Никогда не объединяйте ваш запрос со строкой. Если вы выполните запрос, подобный следующему: «выберите p из Person p, где p.name» + person.getName (), вы можете быть уверены, что хакерам это понравится. Они используют этот тип кода для атаки «SQL-инъекция» (или JPQL-инъекция). Чтобы избежать такого рода атак, добавьте параметры к вашему запросу, как мы увидим ниже.
Ниже вы увидите несколько способов сделать запрос:
| 
 001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
041 
042 
043 
044 
045 
046 
047 
048 
049 
050 
051 
052 
053 
054 
055 
056 
057 
058 
059 
060 
061 
062 
063 
064 
065 
066 
067 
068 
069 
070 
071 
072 
073 
074 
075 
076 
077 
078 
079 
080 
081 
082 
083 
084 
085 
086 
087 
088 
089 
090 
091 
092 
093 
094 
095 
096 
097 
098 
099 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
 | 
package com.main;import java.util.List;import javax.persistence.EntityManager;import javax.persistence.Query;import com.model.Dog;import com.model.Person;public class Page04 { public static void main(String[] args) {  CodeGenerator.startConnection();  CodeGenerator.generateData();  EntityManager em = CodeGenerator.getEntityManager();  List<Dog> dogs = listAllDogs(em);  for (Dog dog : dogs) {   System.out.println(dog.getName());  }  Person person03 = findPersonByName(em, CodeGenerator.PERSON03_NAME);  System.out.println(person03.getName());  Person person01 = new Person();  person01.setId(1);  Person savedPerson = findPersonByPersonObject(em, person01);  System.out.println(savedPerson.getName());  List<Dog> dogsByWeight = listAllDogsOrderingByWeight(em);  for (Dog dog : dogsByWeight) {   System.out.println(dog.getWeight());  }  String addressName = findAddressNameOfPerson(em, CodeGenerator.PERSON04_NAME);  System.out.println('Person 04 address is: ' + addressName);  Person person02 = findPersonByNameWithAllDogs(em, CodeGenerator.PERSON02_NAME);  for (Dog dog : person02.getDogs()) {   System.out.println('Person 02 Dog: ' + dog.getName());  }  Person person05 = findPersonByNameThatMayNotHaveDogs(em, CodeGenerator.PERSON06_NAME);  System.out.println('Is the list of the Dogs from the Person 05 empty? ' + person05.getDogs().size());  CodeGenerator.closeConnection(); } /**  * Easiest way to do a query  */ @SuppressWarnings('unchecked') private static List<Dog> listAllDogs(EntityManager em) {  Query query = em.createQuery('select d from Dog d', Dog.class);  return query.getResultList(); } /**  * Easiest way to do a query with parameters  */ private static Person findPersonByName(EntityManager em, String name) {  Query query = em.createQuery('select p from Person p where name = :name', Person.class);  query.setParameter('name', name);  return (Person) query.getSingleResult(); } /**  * Executes a query that has as parameter an object  */ private static Person findPersonByPersonObject(EntityManager em, Person person) {  Query query = em.createQuery('select p from Person p where p = :person');  query.setParameter('person', person);  return (Person) query.getSingleResult(); } /**  * Query that will list all dogs with an order  */ @SuppressWarnings('unchecked') private static List<Dog> listAllDogsOrderingByWeight(EntityManager em) {  Query query = em.createQuery('select d from Dog d order by d.weight desc', Dog.class);  return query.getResultList(); } /**  * Query that get only a field instead a complete class object  */ private static String findAddressNameOfPerson(EntityManager em, String name) {  Query query = em.createQuery('select p.address.streetName from Person p where p.name = :name');  query.setParameter('name', name);  return (String) query.getSingleResult(); } /**  * Query that will fetch a lazy relationship Be carefull, with this kind of  * query only those who have the relationship will come in the result  */ private static Person findPersonByNameWithAllDogs(EntityManager em, String name) {  Query query = em.createQuery('select p from Person p join fetch p.dogs where p.name = :name', Person.class);  query.setParameter('name', name);  return (Person) query.getSingleResult(); } /**  * With this query will will bring results that may not have arelationship  */ private static Person findPersonByNameThatMayNotHaveDogs(EntityManager em, String name) {  Query query = em.createQuery('select p from Person p left join fetch p.dogs where p.name = :name', Person.class);  query.setParameter('name', name);  return (Person) query.getSingleResult(); }} | 
О коде выше:
- Каждый запрос вызывается как « em.createQuery (« HHH », HHH.class) » с определенным текстом запроса и возвращаемым классом. Вы можете определить возвращаемый класс, например Person.class. Параметр Person.class будет указывать JPA, который является возвращаемым объектом.
 - Мы можем использовать базовые атрибуты в качестве параметров запроса, таких как « p.name =: name » или объект « p =: person ». Если вы используете объект, JPA будет сравнивать по его @ID.
 - Если вы хотите заказать запрос, вам просто нужно сделать: « order by d.weight desc «. Значение заказа по умолчанию — asc, и вам не нужно его записывать.
 - Об объединении вы должны обратить внимание на два вида объединений, которые мы использовали. В методе « findPersonByNameWithAllDogs » мы просто использовали «… Person p join fetch p.dogs …», чтобы вывести список собак. Нам нужно было использовать выборку соединения, потому что список собак помечен атрибутом «lazy»; если бы мы не включили выборку соединения и не выполнили команду типа « person.getDogs () », потребовалась бы другая « поездка » в базу данных. Если вы используете этот запрос, чтобы найти человека, у которого нет собак, JPA не найдет данных в базе данных, независимо от того, есть ли в вашей базе данных человек без собак. Если вы хотите выполнить запрос, который приносит коллекцию извлекаемых собак и людей, у которых есть или нет собак, вам нужно будет использовать « … Person p left join fetch p.dogs… », как мы делали в методе: « findPersonByNameThatMayNotHaveDogs «. « Левая выборка » принесет людей с пустым списком собак.
 
JPQL: Функции: AVG, COUNT, MAX, MIN, TRIM, SUM, UPPER, LOWER, MOD, LENGHT, SQRT; Использование HAVING, GROUP BY
JPQL также имеет много функций, которые помогают нам с запросами. Ниже вы можете увидеть их описание:
- AVG — среднее число
 - COUNT — подсчитывает количество записей, найденных по запросу.
 - MAX — получает более высокое значение столбца
 - MIN — получает нижнее значение столбца
 - TRIM — удаляет пробел в начале / конце текста
 - SUM — Суммирует все значения столбца
 - UPPER — изменяет весь текст столбца в верхний регистр
 - LOWER — изменяет весь текст столбца в нижний регистр
 - MOD — возвращает модуль столбца
 - ДЛИНА — возвращает размер строки
 - SQRT — возвращает квадратный корень числа
 
Ниже вы увидите, как использовать эти функции:
| 
 001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
041 
042 
043 
044 
045 
046 
047 
048 
049 
050 
051 
052 
053 
054 
055 
056 
057 
058 
059 
060 
061 
062 
063 
064 
065 
066 
067 
068 
069 
070 
071 
072 
073 
074 
075 
076 
077 
078 
079 
080 
081 
082 
083 
084 
085 
086 
087 
088 
089 
090 
091 
092 
093 
094 
095 
096 
097 
098 
099 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
 | 
package com.main;import java.util.List;import javax.persistence.EntityManager;import javax.persistence.Query;import com.model.Person;public class Page05 { public static void main(String[] args) {  CodeGenerator.startConnection();  CodeGenerator.generateData();  EntityManager em = CodeGenerator.getEntityManager();  Number average = getPersonsAgeAverage(em);  System.out.println(average);  List<Object[]> personsFilteredByDogsWeight = getPersonsWithDogsWeightHigherThan(em, 4d);  for (Object[] objects : personsFilteredByDogsWeight) {   Person person = (Person) objects[0];   Long count = (Long) objects[1];   System.out.println('The person : ' + person.getName() + ' has ' + count + ' dogs with the weight > 4');  }  List<Object[]> dogsMinAndMaxWeightList = getDogMinAndMaxWeight(em);  Object[] dogMinAndMaxWeightResult = dogsMinAndMaxWeightList.get(0);  System.out.println('Min: ' + dogMinAndMaxWeightResult[0] + ' Max: ' + dogMinAndMaxWeightResult[1]);  Number sumOfAllAges = getTheSumOfAllAges(em);  System.out.println('All summed ages are: ' + sumOfAllAges);  String loweredCaseName = getLoweredCaseNameFromUpperCase(em, CodeGenerator.PERSON03_NAME);  System.out.println(loweredCaseName);  Number personAgeMod = getPersonAgeMode(em, CodeGenerator.PERSON05_NAME, 6);  System.out.println('Person modulus age: ' + personAgeMod);  Number personAgeSqrt = getPersonAgeSqrtUsingTrim(em, '        ' + CodeGenerator.PERSON04_NAME + '        ');  System.out.println('Person modulus age: ' + personAgeSqrt);  List<Object[]> personsByDogsAmount = getPersonByHavingDogAmountHigherThan(em, 3);  for (Object[] objects : personsByDogsAmount) {   Person person = (Person) objects[0];   Long count = (Long) objects[1];   System.out.println(person.getName() + ' has ' + count + ' dogs');  }  CodeGenerator.closeConnection(); } /**  * Uses the AVG sql database function  */ private static Number getPersonsAgeAverage(EntityManager em) {  Query query = em.createQuery('select avg(p.age) from Person p');  return (Number) query.getSingleResult(); } /**  * This query will use the count database function  *  * @return List<Object[]> where object[0] is a person, object [2] is a Long  */ @SuppressWarnings('unchecked') private static List<Object[]> getPersonsWithDogsWeightHigherThan(EntityManager em, double weight) {  Query query = em.createQuery('select p, count(p) from Person p join p.dogs d where d.weight > :weight group by p');  query.setParameter('weight', weight);  return query.getResultList(); } /**  * This query will use the min and max sql database function  *  * @return List<Object[]> where object[0] is the min, object [2] is the max  */ @SuppressWarnings('unchecked') private static List<Object[]> getDogMinAndMaxWeight(EntityManager em) {  Query query = em.createQuery('select min(weight), max(weight) from Dog');  return query.getResultList(); } /**  * This query will use the sum sql database function  */ private static Number getTheSumOfAllAges(EntityManager em) {  Query query = em.createQuery('select sum(p.age) from Person p');  return (Number) query.getSingleResult(); } /**  * Method that uses the UPPER and LOWER database functions  */ private static String getLoweredCaseNameFromUpperCase(EntityManager em, String name) {  Query query = em.createQuery('select lower(p.name) from Person p where UPPER(p.name) = :name');  query.setParameter('name', name.toUpperCase());  return (String) query.getSingleResult(); } /**  * Method that uses the mod database function  */ private static Number getPersonAgeMode(EntityManager em, String personName, int modBy) {  Query query = em.createQuery('select mod(p.age, :modBy) from Person p where p.name = :name');  query.setParameter('modBy', modBy);  query.setParameter('name', personName);  return (Number) query.getSingleResult(); } /**  * Method that uses the square root of a person age using the trim function in the name  */ private static Number getPersonAgeSqrtUsingTrim(EntityManager em, String name) {  Query query = em.createQuery('select sqrt(p.age) from Person p where p.name = trim(:name)');  query.setParameter('name', name);  return (Number) query.getSingleResult(); } /**  * Method that uses the having comparator with count  */ @SuppressWarnings('unchecked') private static List<Object[]> getPersonByHavingDogAmountHigherThan(EntityManager em, long dogAmount) {  Query query = em.createQuery('select p, count(p) from Person p join p.dogs group by p.id having count(p) > :dogAmount');  query.setParameter('dogAmount', dogAmount);  return query.getResultList(); }} | 
О коде выше:
- В методе « getPersonsAgeAverage » мы используем функцию «avg» для вычисления среднего значения столбца age.
 - В методе « getPersonsWithDogsWeightHigherThan » мы используем функцию count, чтобы вывести количество собак с объектом person. Обратите внимание, что у нас есть два разных результата: число и объект person. Эти значения попадут внутрь массива Object [].
 - Функции LOWER и UPPER изменят ваш строковый регистр, и вы можете использовать его для изменения результата запроса (после выбора) или в условии where. Метод « getLoweredCaseNameFromUpperCase » использует функции LOWER и UPPER в обоих случаях.
 - « GetPersonAgeMode » использует параметр после слова select. С JPA мы можем использовать параметр в любом месте запроса, вам просто нужно добавить «:» с переменной. Вы можете иметь один и тот же параметр несколько раз и передавать значение с помощью метода query.setParameter.
 - В методе « getPersonByHavingDogAmountHigherThan » функция « has » вызывается с помощью функции « count ». Мы можем использовать функцию « имея », чтобы помочь нам отфильтровать результат данных запроса.
 
JPQL: Условия фильтрации: LIKE, IN, DISTINCT, EMPTY, BETWEEN, NULL, MEMBER OF, EXISTS (подзапросы), ANY, ALL, SOME, CONCAT, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, LOCATE, SIZE, SUBST
Некоторые из этих функций имеют одну и ту же цель, но обрабатываются по-разному.
Ниже вы можете увидеть, как использовать эти функции:
| 
 001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
041 
042 
043 
044 
045 
046 
047 
048 
049 
050 
051 
052 
053 
054 
055 
056 
057 
058 
059 
060 
061 
062 
063 
064 
065 
066 
067 
068 
069 
070 
071 
072 
073 
074 
075 
076 
077 
078 
079 
080 
081 
082 
083 
084 
085 
086 
087 
088 
089 
090 
091 
092 
093 
094 
095 
096 
097 
098 
099 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167 
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179 
180 
181 
182 
183 
184 
185 
186 
187 
188 
189 
190 
191 
192 
193 
194 
195 
196 
197 
198 
199 
200 
201 
202 
203 
204 
205 
206 
207 
208 
209 
210 
211 
212 
213 
214 
215 
216 
217 
218 
219 
220 
221 
222 
223 
224 
225 
226 
227 
228 
229 
230 
231 
232 
233 
234 
235 
236 
237 
238 
239 
240 
241 
242 
243 
244 
 | 
package com.main;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import javax.persistence.EntityManager;import javax.persistence.Query;import com.model.Dog;import com.model.Person;public class Page06 { public static void main(String[] args) {  CodeGenerator.startConnection();  CodeGenerator.generateData();  EntityManager em = CodeGenerator.getEntityManager();  List<Person> personByLike = getPersonByNameUsingLike(em, 'oh');  for (Person person : personByLike) {   System.out.println(person.getName());  }  List<Person> personsByAdressNumber = getPersonsByAddressNumberHigherThan(em, 90);  for (Person person : personsByAdressNumber) {   System.out.println(person.getName());  }  List<Person> personsWithoutDogs = getPersonsWithoutDogs(em);  System.out.println('Total of persons without dogs: ' + personsWithoutDogs.size());  List<Person> personsWithoutAddress = getPersonsWithoutAddress(em);  System.out.println('Total of persons without address: ' + personsWithoutAddress.size());  try {   SimpleDateFormat formatter = new SimpleDateFormat('dd/MM/yyyy');   Date startDate = formatter.parse('01/01/1996');   Date endDate = formatter.parse('01/01/1999');   List<Dog> dogsByBirth = getDogByBirthDate(em, startDate, endDate);   for (Dog dog : dogsByBirth) {    System.out.println(dog.getName() + ': ' + formatter.format(dog.getDateOfBirth()));   }  } catch (Exception e) {   e.printStackTrace();  }  Dog dog = (Dog) em.createQuery('select d from Dog d where d.id = 1', Dog.class).getSingleResult();  boolean belongsTo = isThisDogBelongingToAperson(em, dog, CodeGenerator.PERSON01_NAME);  System.out.println('Is this Dog member of Perons01? ' + belongsTo);  Person personByConcatedName = getPersonConcatingName(em, 'Ma', 'ry');  System.out.println('Found the person? ' + personByConcatedName.getName());  List<Person> personByLocate = getPersonByLocatingStringInTheName(em, 'Mary');  System.out.println('Amount of persons found by locate: ' + personByLocate.size());  String personNameBySubstring = getPersonNameBySubstring(em, CodeGenerator.PERSON06_NAME, 12, 18);  System.out.println('Name substring is: ' + personNameBySubstring);  List<Person> personsDogWeight = getPersonByDogWeightOnlyHigherThan(em, 20);  for (Person person : personsDogWeight) {   System.out.println(person.getName());  }  List<Person> distinctPersons = getDistinctPersonsByDogsWeight(em, 2d);  System.out.println('With the distinct, the result size is: ' + distinctPersons.size());  List<Person> personsWithDogsAmount = getPersonsWithDougsAmountOf(em, 4);  System.out.println('Number of persons with 4 dogs: ' + personsWithDogsAmount.size());  Number numberOfDogsByPerson = getDogAmountByPerson(em, CodeGenerator.PERSON04_NAME);  System.out.println('The dog amount is to ' + CodeGenerator.PERSON04_NAME + ': ' + numberOfDogsByPerson);  List<Dog> dogsBornedAfterToday = getDogsBornAfterToday(em);  System.out.println('The amount of dogs borned after today is: ' + dogsBornedAfterToday.size());  CodeGenerator.closeConnection(); } /**  * This methods compares a value with LIKE  */ @SuppressWarnings('unchecked') private static List<Person> getPersonByNameUsingLike(EntityManager em, String name) {  Query query = em.createQuery('select p from Person p where p.name like :name');  query.setParameter('name', '%' + name + '%');  return query.getResultList(); } /**  * This methods show several ways to do a query that checks if a part of a collection is inside another  */ @SuppressWarnings('unchecked') private static List<Person> getPersonsByAddressNumberHigherThan(EntityManager em, int houseNumber) {  Query query = em.createQuery('select p from Person p where p.address in (select a from Address a where a.houseNumber > :houseNumber)');  // Query query = em.createQuery('select p from Person p where (select a from Address a where a.houseNumber > :houseNumber and p.address = a) > 0');  // Query query = em.createQuery('select p from Person p where p.address = any (select a from Address a where a.houseNumber > :houseNumber)');  // Query query = em.createQuery('select p from Person p where p.address = some (select a from Address a where a.houseNumber > :houseNumber)');  // Query query = em.createQuery('select p from Person p where exists (select a from p.address a where a.houseNumber > :houseNumber)');  query.setParameter('houseNumber', houseNumber);  return query.getResultList(); } /**  * This methods show how to check if a collection is empty  */ @SuppressWarnings('unchecked') private static List<Person> getPersonsWithoutDogs(EntityManager em) {  Query query = em.createQuery('select p from Person p where p.dogs is empty');  return query.getResultList(); } /**  * This method shows two ways to check if a relationship @OneToOne is empty  */ @SuppressWarnings('unchecked') private static List<Person> getPersonsWithoutAddress(EntityManager em) {  Query query = em.createQuery('select p from Person p where p.address is null');  // Query query = em.createQuery('select p from Person p where p.address is empty');  return query.getResultList(); } /**  * Method that uses the between comparation  */ @SuppressWarnings('unchecked') private static List<Dog> getDogByBirthDate(EntityManager em, Date startDate, Date endDate) {  Query query = em.createQuery('select d from Dog d where d.dateOfBirth between :startDate and :endDate');  query.setParameter('startDate', startDate);  query.setParameter('endDate', endDate);  return query.getResultList(); } /**  * Method that uses the member of comparation to check if an object belogs to a collection  */ private static boolean isThisDogBelongingToAperson(EntityManager em, Dog dog, String name) {  Query query = em.createQuery('select p from Person p where :dog member of p.dogs and p.name = :name');  query.setParameter('dog', dog);  query.setParameter('name', name);  try {   return query.getSingleResult() != null;  } catch (Exception e) {   return false;  } } /**  * Methods that concats Strings  */ private static Person getPersonConcatingName(EntityManager em, String firstWord, String secondWord) {  Query query = em.createQuery('select p from Person p where p.name = concat(:firstWord, :secondWord)', Person.class);  query.setParameter('firstWord', firstWord);  query.setParameter('secondWord', secondWord);  return (Person) query.getSingleResult(); } /**  * Method that locates a string inside another  */ @SuppressWarnings('unchecked') private static List<Person> getPersonByLocatingStringInTheName(EntityManager em, String valueToBeLocated) {  Query query = em.createQuery('select p from Person p where locate(p.name, :value) > 0', Person.class);  query.setParameter('value', valueToBeLocated);  return query.getResultList(); } /**  * Methods that uses the ALL comparator  */ @SuppressWarnings('unchecked') private static List<Person> getPersonByDogWeightOnlyHigherThan(EntityManager em, double weight) {  Query query = em.createQuery('select p from Person p where p.dogs is not empty and :weight < all (select d.weight from p.dogs d)');  query.setParameter('weight', weight);  return query.getResultList(); } /**  * Method that uses the distinct to remove any repetetition  */ @SuppressWarnings('unchecked') private static List<Person> getDistinctPersonsByDogsWeight(EntityManager em, double weight) {  Query query = em.createQuery('select distinct p from Person p join p.dogs d where d.weight > :weight');  query.setParameter('weight', weight);  return query.getResultList(); } /**  * Method that uses the substring to get just a position of chars inside the string  */ private static String getPersonNameBySubstring(EntityManager em, String personName, int startPosition, int endPosition) {  Query query = em.createQuery('select substring(p.name, :startPosition, :endPosition) from Person p where p.name = :personName');  query.setParameter('personName', personName);  query.setParameter('startPosition', startPosition);  query.setParameter('endPosition', endPosition);  return (String) query.getSingleResult(); } /**  * Method that checks the size of a collection  */ @SuppressWarnings('unchecked') private static List<Person> getPersonsWithDougsAmountOf(EntityManager em, int dogAmount) {  Query query = em.createQuery('select p from Person p where size(p.dogs) = :dogAmount');  query.setParameter('dogAmount', dogAmount);  return query.getResultList(); } /**  * Method that gets the size of a collection  */ private static Number getDogAmountByPerson(EntityManager em, String personName) {  Query query = em.createQuery('select size(p.dogs) from Person p where p.name = :personName');  query.setParameter('personName', personName);  return (Number) query.getSingleResult(); } /**  * Methods that uses the current database server date/time  */ @SuppressWarnings('unchecked') private static List<Dog> getDogsBornAfterToday(EntityManager em) {  Query query = em.createQuery('select d from Dog d where d.dateOfBirth > CURRENT_DATE');  return query.getResultList(); }} | 
О коде выше:
- Вы можете добавить слово «НЕ» в свои запросы. Если вы используете « IS EMPTY », вы будете искать коллекцию без значений; Если вы используете « НЕ ПУСТО », вы будете искать заполненную коллекцию.
 - « GetPersonsByAddressNumberHigherThan » показывает, как выполнить один и тот же запрос с разными функциями. Все закомментированные командные строки принесут одинаковый результат. В / Any / Some / Exists есть близкий синтаксис. Согласно Pro EJB3 книга « Некоторые » является псевдонимом «Любой».
 - Компаратор « IS EMPTY » может использоваться для проверки коллекции (например, @OneToMany) или класса отношений (например, @OneToOne). Компаратор « IS NULL » не может проверить коллекцию, но вы можете использовать его для проверки атрибута не коллекции (например, @OneToOne).
 - Компаратор « MEMBER OF » проверит, принадлежит ли данный параметр коллекции.
 - Функция «CONCAT» может использоваться как компаратор условий или как результат запроса. В приведенном выше коде он использовался просто как компаратор, но вы можете использовать его так: «выберите concat (firstName, lastName) из Person p»
 - В методе « getPersonByDogWeightOnlyHigherThan » мы используем оператор ALL. Этот оператор вернет true, только если все элементы условия (« : weight> ALL» ) вернут true. В этом методе он вернет истину, только если вес всех собак-людей был больше, чем «: вес», если только одна из собак получила вес с меньшим значением, компаратор возвратил бы ложь. Вы должны знать, если список пуст, компаратор вернет true . Чтобы избежать такого поведения, вам нужно проверить, является ли список пустым, как это было сделано в методе: « p.dogs не пуст ».
 - « Отличная » функция удалит дублирующиеся объекты. В методе « getDistinctPersonsByDogsWeight » « отличная » функция удаляет дублированных лиц.
 - Функция « SUBSTRING » извлекает значение из заданной строки. Вы установите начало и конец значения, которое будет извлечено из исходного значения. Вы можете использовать эту функцию в качестве компаратора также.
 - Функция « SIZE » возвращает количество элементов внутри коллекции. Вы можете использовать в качестве компаратора или получить значение.
 - В приведенном выше коде мы используем функцию « CURRENTE_DATE » для сравнения даты, вы также можете использовать « CURRENT_TIME, CURRENT_TIMESTAMP ». В спецификации JPA говорится, что функции текущей даты могут использоваться только в качестве компаратора. JPA пока не поддерживает никакие функции для извлечения текущей даты базы данных, поскольку эта функция не является переносимой базой данных ( 4.6.16. Функциональные выражения — окончательный выпуск JSR-000220 Enterprise JavaBeans 3.0 (постоянство) ). Если вы хотите запросить дату в базе данных, вы можете использовать NativeQuery, чтобы получить это значение.
 - Я всегда должен помнить, что вы не можете перемещаться внутри коллекции. Вы не можете выполнить следующую команду: «person.dogs.name». Вы можете получить доступ к имени собаки с помощью команды, такой как: выберите p из Person p, вызовите соединение p.dogs d, где d.name = » .
 
Продолжаем вторую часть серии.
Ссылка: JPA Запросы и советы от нашего партнера JCG Хеберта Коэльо в блоге uaiHebert .

