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 – 将该文件夹包含为项目的源文件夹。