1. 概述

Querydsl 是一个扩展的 Java 框架,它有助于 以类似于 SQL 的特定于域的语言创建和运行类型安全的查询

在本文中,我们将使用 Java Persistence API 探索 Querydsl。

这里需要注意的是,HQL for Hibernate 是 Querydsl 的第一个目标语言,但现在它支持 JPA、JDO、JDBC、Lucene、Hibernate Search、MongoDB、Collections 和 RDFBean 作为后端。

2. 准备工作

我们首先将必要的依赖项添加到我们的 Maven 项目中:

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

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

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

现在让我们配置 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>

JPAAnnotationProcessor 将查找使用 jakarta.persistence.Entity 注释进行注释的域类型,并为它们生成查询类型。

3. 使用 Querydsl 进行查询

查询是根据生成的反映域类型属性的查询类型构建的。此外,函数/方法调用是以完全类型安全的方式构造的。

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

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 将在与 Person 相同的包中生成一个简单名称为 QPerson 的 查询类型。 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 是一个 JPA EntityManager

现在让我们检索所有名字为“ Kent ”的人作为一个简单的例子:

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

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

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

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

或者:

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.订购

我们首先按 姓氏 字段对结果进行降序排序:

QPerson person = QPerson.person;
List<Person> 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 形式返回,其中 名字 为键, 最大年龄 为值:

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

5. 使用 Querydsl 进行测试

现在,让我们使用 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);
}

现在让我们使用这个新的 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"));
}

六,结论

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

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

这里需要注意的是 – 运行一个简单的 Maven 构建(mvn clean install)以将类型生成到 target/ generated-sources – 然后,如果您使用 Eclipse – 将该文件夹包含为项目的源文件夹。