A Guide to Querydsl with JPA – 使用JPA的Querydsl指南

最后修改: 2016年 3月 12日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Querydsl is an extensive Java framework, which helps with creating and running type-safe queries in a domain specific language that is similar to SQL.

Querydsl是一个广泛的Java框架,它有助于在类似于SQL的特定领域语言中创建和运行类型安全的查询

In this article we’ll explore Querydsl with the Java Persistence API.

在这篇文章中,我们将用Java Persistence API探索Querydsl。

A quick side note here is that HQL for Hibernate was the first target language for Querydsl, but nowadays it supports JPA, JDO, JDBC, Lucene, Hibernate Search, MongoDB, Collections and RDFBean as backends.

这里有一个简单的附带说明,HQL for Hibernate是Querydsl的第一个目标语言,但现在它支持JPA、JDO、JDBC、Lucene、Hibernate Search、MongoDB、Collection和RDFBean作为后端。

2. Preparations

2.准备工作

Let’s first add the necessary dependencies into our Maven project:

首先,让我们在Maven项目中添加必要的依赖项。

<properties>
    <querydsl.version>2.5.0</querydsl.version>
</properties>

<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-apt</artifactId>
    <version>${querydsl.version}</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
    <version>${querydsl.version}</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.1</version>
</dependency>

And now let’s configure the Maven APT plugin:

现在我们来配置Maven的APT插件。

<project>
    <build>
    <plugins>
    ...
    <plugin>
        <groupId>com.mysema.maven</groupId>
        <artifactId>apt-maven-plugin</artifactId>
        <version>1.1.3</version>
        <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources</outputDirectory>
                <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
        </execution>
        </executions>
    </plugin>
    ...
    </plugins>
    </build>
</project>

The JPAAnnotationProcessor will find domain types annotated with javax.persistence.Entity annotation and generates query types for them.

JPAAnnotationProcessor将找到用javax.persistence.Entity注解的域类型,并为其生成查询类型。

3. Queries With Querydsl

3.使用Querydsl的查询

Queries are constructed based on generated query types that reflect the properties of your domain types. Also function/method invocations are constructed in a fully type-safe manner.

查询是基于生成的查询类型构建的,这些类型反映了你的领域类型的属性。同时,函数/方法的调用是以完全类型安全的方式构建的。

The query paths and operations are the same in all implementations and also the Query interfaces have a common base interface.

查询路径和操作在所有的实现中都是相同的,而且查询接口也有一个共同的基础接口。

3.1. An Entity and the Querydsl Query Type

3.1.一个实体和Querydsl查询类型

Let’s first define a simple entity we’re going to make use of as we go through examples:

让我们首先定义一个简单的实体,我们将在举例时加以利用。

@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 will generate a query type with the simple name QPerson into the same package as Person. QPerson can be used as a statically typed variable in Querydsl queries as a representative for the Person type.

Querydsl将生成一个简单名称为QPerson的查询类型,与Person放入同一个包。QPerson可以作为静态类型的变量在Querydsl查询中使用,作为Person类型的代表。

First – QPerson has a default instance variable which can be accessed as a static field:

首先–QPerson有一个默认的实例变量,可以作为一个静态字段被访问。

QPerson person = QPerson.person;

Alternatively you can define your own Person variables like this:

或者,你可以像这样定义你自己的Person变量。

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

3.2. Build Query Using JPAQuery

3.2.使用JPAQuery建立查询。

We can now use JPAQuery instances for our queries:

我们现在可以使用JPAQuery实例进行查询。

JPAQuery query = new JPAQuery(entityManager);

Note that the entityManager is a JPA EntityManager.

请注意,entityManager是一个JPA EntityManager

Let’s now retrieve all the persons with the first name “Kent” as a quick example:

现在让我们检索所有名字为”Kent“的人,作为一个快速的例子。

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

The from call defines the query source and projection, the where part defines the filter and list tells Querydsl to return all matched elements.

from调用定义了查询源和投影,where部分定义了过滤器,list告诉Querydsl返回所有匹配元素。

We can also use multiple filters:

我们还可以使用多个过滤器。

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")));

In native JPQL form the query would be written like this:

在本地的JPQL形式中,查询将被写成这样。

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

If you want to combine the filters via “or” then use the following pattern:

如果你想通过 “或 “来组合过滤器,那么使用以下模式。

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

4. Ordering and Aggregation in Querydsl

4.Querydsl中的排序和聚合

Let’s now have a look at how ordering and aggregation work within the Querydsl library.

现在让我们来看看在Querydsl库中排序和聚合是如何工作的。

4.1. Ordering

4.1.订购

We’ll start by ordering our results in descending order by the surname field:

我们先按surname字段以降序排列我们的结果。

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

4.2. Aggregation

4.2.聚合

Let’s now use a simple aggregation, as we do have a few available (Sum, Avg, Max, Min):

现在让我们使用一个简单的聚合,因为我们确实有一些可用的聚合(Sum, Avg, Max, Min)。

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

4.3. Aggregation With GroupBy

4.3.用GroupBy进行聚合

The com.mysema.query.group.GroupBy class provides aggregation functionality which we can use to aggregate query results in memory.

com.mysema.query.group.GroupBy类提供了聚合功能,我们可以用它来聚合内存中的查询结果。

Here’s a quick example where the result are returned as Map with firstname as the key and max age as the value:

这里有一个快速的例子,结果以Map形式返回,firstname为键,max age为值。

QPerson person = QPerson.person;   
Map<String, Integer> results = 
  query.from(person).transform(
      GroupBy.groupBy(person.firstname).as(GroupBy.max(person.age)));

5. Testing With Querydsl

5.使用Querydsl进行测试

Now, let’s define a DAO implementation using Querydsl – and let’s define the following search operation:

现在,让我们使用Querydsl定义一个DAO实现–让我们定义下面的搜索操作。

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

And now let’s build a few tests using this new DAO and let’s use Querydsl to search for newly created Person objects (implemented in PersonDao class) and in another test aggregation using GroupBy class is tested:

现在让我们使用这个新的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<String, Integer> maxAge = personDao.findMaxAgeByName();
    Assert.assertTrue(maxAge.size() == 2);
    Assert.assertSame(35, maxAge.get("Ralph"));
    Assert.assertSame(30, maxAge.get("Kent"));
}

6. Conclusion

6.结论

This tutorial illustrated how to build JPA project using Querydsl.

本教程说明了如何使用Querydsl建立JPA项目。

The full implementation of this article can be found in the github project – this is an Eclipse based maven project, so it should be easy to import and run as it is.

本文的完整实现可以在github项目中找到–这是一个基于Eclipse的maven项目,所以应该很容易导入并按原样运行。

A quick note here is – run a simple maven build (mvn clean install) to generate the types into target/generated-sources – and then, if you’re using Eclipse – include the folder as a source folder of the project.

这里要说明的是–运行简单的maven构建(mvn clean install),将这些类型生成target/generated-sources–然后,如果你使用Eclipse–将该文件夹作为项目的源文件夹。