Руководство по Querydsl с JPA

Руководство по Querydsl с JPA

1. обзор

Querydsl - это обширная среда Java, помогающая создавать и запускатьtype-safe queries in a domain specific language that is similar to SQL.

В этой статье мы исследуем Querydsl с Java Persistence API.

Вкратце отметим, что HQL для Hibernate был первым целевым языком для Querydsl, но в настоящее время он поддерживает JPA, JDO, JDBC, Lucene, Hibernate Search, MongoDB, Collections и RDFBean в качестве бэкэндов.

2. Препараты

Давайте сначала добавим необходимые зависимости в наш проект Maven:


    2.5.0



    com.querydsl
    querydsl-apt
    ${querydsl.version}
    provided



    com.querydsl
    querydsl-jpa
    ${querydsl.version}



    org.slf4j
    slf4j-log4j12
    1.6.1

А теперь давайте настроим плагин Maven APT:


    
    
    ...
    
        com.mysema.maven
        apt-maven-plugin
        1.1.3
        
        
            
                process
            
            
                target/generated-sources
                com.querydsl.apt.jpa.JPAAnnotationProcessor
            
        
        
    
    ...
    
    

JPAAnnotationProcessor найдет типы доменов, аннотированные аннотациейjavax.persistence.Entity, и сгенерирует для них типы запросов.

3. Запросы с Querydsl

Запросы строятся на основе сгенерированных типов запросов, которые отражают свойства типов вашего домена. Также вызовы функций / методов создаются полностью безопасным для типов образом.

Пути запросов и операции одинаковы во всех реализациях, а также интерфейсыQuery имеют общий базовый интерфейс.

3.1. Сущность и тип запроса Querydsl

Давайте сначала определим простую сущность, которую мы собираемся использовать при рассмотрении примеров:

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String firstname;

    @Column
    private String surname;

    Person() {
    }

    public Person(String firstname, String surname) {
        this.firstname = firstname;
        this.surname = surname;
    }

    // standard getters and setters

}

Querydsl сгенерирует тип запроса с простым именемQPerson в том же пакете, что иPerson. QPerson можно использовать в качестве статически типизированной переменной в запросах Querydsl как представителя типаPerson.

Во-первых,QPerson имеет переменную экземпляра по умолчанию, доступ к которой можно получить как статическое поле:

QPerson person = QPerson.person;

В качестве альтернативы вы можете определить свои собственные переменныеPerson следующим образом:

QPerson person = new QPerson("Erich", "Gamma");

3.2. Построить запрос с использованиемJPAQuery

Теперь мы можем использовать экземплярыJPAQuery для наших запросов:

JPAQuery query = new JPAQuery(entityManager);

Обратите внимание, чтоentityManager - это JPAEntityManager.

Давайте теперь извлечем всех людей с именем «Kent» в качестве быстрого примера:

QPerson person = QPerson.person;
List persons = query.from(person).where(person.firstName.eq("Kent")).list(person);

Вызовfrom определяет источник запроса и проекцию, частьwhere определяет фильтр, аlist сообщает Querydsl вернуть все согласованные элементы.

Мы также можем использовать несколько фильтров:

query.from(person).where(person.firstName.eq("Kent"), person.surname.eq("Beck"));

Or:

query.from(person).where(person.firstName.eq("Kent").and(person.surname.eq("Beck")));

В нативном JPQL из запроса будет написано так:

select person from Person as person where person.firstName = "Kent" and person.surname = "Beck"

Если вы хотите объединить фильтры через «или», используйте следующий шаблон:

query.from(person).where(person.firstName.eq("Kent").or(person.surname.eq("Beck")));

4. Упорядочивание и агрегирование в Querydsl

Давайте теперь посмотрим, как упорядочивание и агрегирование работают в библиотеке Querydsl.

4.1. заказ

Начнем с сортировки результатов в порядке убывания по полюsurname:

QPerson person = QPerson.person;
List persons = query.from(person)
    .where(person.firstname.eq(firstname))
    .orderBy(person.surname.desc())
    .list(person);

4.2. агрегирование

Давайте теперь воспользуемся простым агрегированием, так как у нас есть несколько доступных (Sum, Avg, Max, Min):

QPerson person = QPerson.person;
int maxAge = query.from(person).list(person.age.max()).get(0);

4.3. Агрегация сGroupBy

Классcom.mysema.query.group.GroupBy предоставляет функции агрегирования, которые мы можем использовать для агрегирования результатов запроса в памяти.

Вот быстрый пример, в котором результат возвращается какMap сfirstname в качестве ключа иmax age в качестве значения:

QPerson person = QPerson.person;
Map results =
  query.from(person).transform(
      GroupBy.groupBy(person.firstname).as(GroupBy.max(person.age)));

5. Тестирование с помощью Querydsl

Теперь давайте определим реализацию DAO с помощью Querydsl и определим следующую операцию поиска:

public List findPersonsByFirstnameQuerydsl(String firstname) {
    JPAQuery query = new JPAQuery(em);
    QPerson person = QPerson.person;
    return query.from(person).where(person.firstname.eq(firstname)).list(person);
}

А теперь давайте создадим несколько тестов, используя этот новый DAO, и давайте воспользуемся Querydsl для поиска вновь созданных объектовPerson (реализованных в классеPersonDao), а в другом тестовом агрегате с использованием классаGroupBy будет протестировано :

@Autowired
private PersonDao personDao;

@Test
public void givenExistingPersons_whenFindingPersonByFirstName_thenFound() {
    personDao.save(new Person("Erich", "Gamma"));
    Person person = new Person("Kent", "Beck");
    personDao.save(person);
    personDao.save(new Person("Ralph", "Johnson"));

    Person personFromDb =  personDao.findPersonsByFirstnameQuerydsl("Kent").get(0);
    Assert.assertEquals(person.getId(), personFromDb.getId());
}

@Test
public void givenExistingPersons_whenFindingMaxAgeByName_thenFound() {
    personDao.save(new Person("Kent", "Gamma", 20));
    personDao.save(new Person("Ralph", "Johnson", 35));
    personDao.save(new Person("Kent", "Zivago", 30));

    Map maxAge = personDao.findMaxAgeByName();
    Assert.assertTrue(maxAge.size() == 2);
    Assert.assertSame(35, maxAge.get("Ralph"));
    Assert.assertSame(30, maxAge.get("Kent"));
}

6. Заключение

В этом уроке показано, как построить проект JPA с использованием Querydsl.

full implementation в этой статье можно найти вin the github project - это проект maven на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.

Небольшое примечание: запустите простую сборку maven (mvn clean install), чтобы сгенерировать типы вtarget/generated-sources, а затем, если вы используете Eclipse, включите эту папку в качестве исходной папки проекта.