Статьи

JPA 2.0 Критерий Запрос с Hibernate

Критерий Query был введен в JPA 2.0. С помощью критериальных запросов вы можете написать свои запросы безопасным для типов способом. Перед критериями запросов разработчикам приходилось писать запросы посредством построения определений запросов на основе объектов. Возможны неправильные синтаксисы при построении запросов. API запроса критериев предоставляет возможность создавать структурированные и вложенные запросы с безопасностью времени компиляции. Попадание в теорию запросов о критериях может быть не очень хорошей идеей, поскольку в сети можно найти множество страниц для одного и того же. Давайте рассмотрим простой пример для понимания запроса с использованием критерия запроса. В этом посте я использовал hibernate в качестве поставщика с JPA 2.0, чтобы показать пример Criteria Query.
Прежде чем углубляться в запрос критериев, давайте подумаем о таблицах базы данных и соответствующих Java-классах, которые могут быть представлены в виде сущностей:

Таблицы базы данных:

Например, у нас есть две таблицы базы данных:

    1. State [stateId, stateName]
    2. Город [cityId, штатный (FK #), CityName]
Мы хотим получить список городов для определенного штата, где название города должно начинаться с буквы «M», а список городов должен быть в порядке возрастания. Если мы подумаем о простом нативном SQL, это будет выглядеть так:
1
Select * from City c, State s where c.stateId = s.stateId and c.stateId = ? and c.cityName like "M%" order by c.cityName

JPA объекты:

Ниже приведены два Java-класса, настроенные как объекты JPA для представления таблиц состояний и городов. Они также могут быть получены с использованием инструмента обратного инжиниринга .

Java-сущность для таблицы STATE

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
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.Date;
import java.util.Set;
import javax.persistence.SequenceGenerator;
 
@Entity
@Table(name="STATE")
@SequenceGenerator(sequenceName="STATE_SEQ",name="STATE_SEQ_GEN")
public class State {
    private Long stateId;
    private String stateName;
    private Set citySet;
    @Id
    @Column(name="stateId")
    @GeneratedValue(generator="STATE_SEQ_GEN",strategy=GenerationType.SEQUENCE)
    public Long getStateId;() {
       return stateId;
    }
    public void setId(long stateId) {
        stateId = stateId;
    }
 
   @Column(name="stateName")
    public String getStateName() {
        return stateName;
    }
    public void setStateName(String stateName) {
        this.stateName = stateName;
    }
    public void setCitySet(Set citySet)
        this.citySet= citySet;
    }
 
    @OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="state")
    public Set getCitySet() {
        return citySet;
    }
}

Java-сущность для таблицы CITY

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
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
 
@Entity
@Table(name="CITY")
@SequenceGenerator(sequenceName="CITY_SEQ",name="CITY_SEQ_GEN")
public class City {
    private Long cityId;
    private String cityName;
    private State state;
 
    public void setId(long cityId) {
        this.cityId = cityId;
    }
 @Id
 @Column(name="CityId")
 @GeneratedValue(generator="CITY_SEQ_GEN",strategy=GenerationType.SEQUENCE)
    public Long getCityId() {
        return cityId;
    }
    @Column(name="CityName")
    public void setContent(String cityName) {
        this.cityName = cityName;
    }
    public String getCityName() {
        return cityName;
    }
    public void setState(State state) {
        this.state = state;
    }
   @ManyToOne(fetch =  FetchType.LAZY)
   @JoinColumn(name = "STATEID", nullable = false)
    public state getState() {
        return state;
    }
}

Объекты значения (POJO):

Ниже приведены два объекта значения. С помощью запроса критериев вы можете напрямую сопоставить свои объекты значений из данных результатов. Вам не нужно писать код для копирования данных результатов из классов сущностей в объекты значений. Это действительно интересная функция в запросе критериев.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
public class StateVO {
    private Long stateId;
    private String stateName;
    private Set cityVOSet;
   // All getter setters
 }
public class CityVO {
    private Long cityId;
    private String cityName;
    private StateVO stateVO;
    public CityVO( Long cityId, String cityName){
                  this.cityId=cicityId;
                  this.cityName=cityName;
    }
    // All getter setters
}

Реализация DAO:

Теперь это время, когда мы можем использовать критерии запроса для получения данных. Мы представим метод, который примет входной аргумент как StateVO и вернет список CityVO.
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
import javax.persistence.EntityManager;
     import javax.persistence.EntityManagerFactory;
     import javax.persistence.Persistence;
     public class StateCityDAOImpl{
      
     public List getCityList(StateVO searchStateVO)  {
       // Get the entity manager instance
       EntityManagerFactory emf = Persistence.createEntityManagerFactory("StateCityService");
       EntityManager entityManager= emf.createEntityManager();
    
       // Get the criteria builder instance from entity manager
      final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
      
     // Create criteria query and pass the value object which needs to be populated as result
      final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(CityVO.class);
    
      // Tell to criteria query which tables/entities you want to fetch
      // To join the City and State tables, we need to write below code
      final Root stateRoot = criteriaQuery.from(State.class);
      final Root cityRoot = criteriaQuery.from(City.class);
  
     // Time to define where clause in terms of Predicates
      // This list will contain all Predicates (where clauses)
      List criteriaList = new ArrayList();
   
     // Note: Ensure that whatever string you are passing in root variables
      // It should be matched with variables' name in entity classes
    
      // [1] where condition: State.StateId = City.StateId
      Predicate predicate1 = criteriaBuilder.equal(
              cityRoot. get("state"). get("stateId"),
              stateRoot.  get("stateId"));
      criteriaList.add(predicate1);
 
      // [2] where condition: City.StateId = ?
      if (searchStateVO.getStateId() != null) {
         Predicate predicate2= criteriaBuilder.equal(
                  cityRoot. get("state"). get("stateId"),
                  searchStateVO.getStateId());
          criteriaList.add(predicate2);
      }
 
      // [3] where condition: City.cityName like 'M%'
      Predicate predicate3
                = criteriaBuilder.like(criteriaBuilder.upper(cityRoot. get("cityName")),
                    "M%");
          criteriaList.add(predicate3); 
    
      // This statement maps your CityVO with result data
      // You have to have a custom constructor in CityVO  (see above) to populate the result data  
      criteriaQuery.select(criteriaBuilder.construct(CityVO.class, cityRoot. get("cityId"),
              cityRoot. get("cityName")));
 
      // Pass the criteria list to the where method of criteria query
      criteriaQuery.where(criteriaBuilder.and(criteriaList.toArray(new Predicate[0])));
 
      // Order by clause based on city names
      criteriaQuery.orderBy(criteriaBuilder.asc(cityRoot. get("cityName")));
 
      // Here entity manager will create actual SQL query out of criteria query
      final TypedQuery query = entityManager.createQuery(criteriaQuery);
     
      // This code can be used to define the row range to fetch the result
      /* if (CitySize != 0) {
          query.setFirstResult(startIndex); // starting row index
          query.setMaxResults(endIndex); //  end row index
     }*/
      return query.getResultList();
}
Теперь у нас есть список CityVO как ответ в вашей руке. Мы можем получить доступ к соответствующему названию города на основании нашего вышеупомянутого требования.
Хотя написание запросов с использованием критериев запроса может быть немного неуклюжим, но как только вы станете удобнее, вам понравится Criteria Query.

Ссылка: JPA 2.0 Критерии Запрос с Hibernate от нашего партнера JCG Нарендры Вермы в блоге NS.Infra .