Derived Query Methods in Spring Data JPA Repositories – Spring Data JPA存储库中的派生查询方法

最后修改: 2019年 5月 13日

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

1. Overview

1.概述

For simple queries, it’s easy to derive what the query should be just by looking at the corresponding method name in our code.

对于简单的查询,很容易推导出查询应该是什么只需查看我们代码中相应的方法名称即可

In this tutorial, we’ll explore how Spring Data JPA leverages this idea in the form of a method naming convention.

在本教程中,我们将探讨Spring Data JPA如何以方法命名约定的形式利用这一理念。

2. Structure of Derived Query Methods in Spring

2.Spring中派生查询方法的结构

Derived method names have two main parts separated by the first By keyword:

派生方法名称有两个主要部分,由第一个By关键词分隔。

List<User> findByName(String name)

The first part — such as find — is the introducer, and the rest — such as ByName — is the criteria.

第一部分–如find–是introducer,其余部分–如ByName–是criteria

Spring Data JPA supports find, read, query, count and get. So, we could have done queryByName, and Spring Data would behave the same.

Spring Data JPA支持findreadquerycountget因此,我们可以做queryByName,Spring Data的行为也是如此。

We can also use Distinct, First or Top to remove duplicates or limit our result set:

我们还可以使用DistinctFirstTop来删除重复的内容或限制我们的结果集

List<User> findTop3ByAge()

The criteria part contains the entity-specific condition expressions of the query. We can use the condition keywords along with the entity’s property names.

标准部分包含查询的实体特定条件表达式。我们可以将条件关键字与实体的属性名称一起使用。

We can also concatenate the expressions with And and Or, as we’ll see in just a moment.

我们还可以用AndOr来连接表达式,我们马上就会看到。

3. Sample Application

3.申请书样本

First, we’ll of course need an application using Spring Data JPA.

首先,我们当然需要一个使用Spring Data JPA的应用程序

In that application, let’s define an entity class:

在该应用中,让我们定义一个实体类。

@Table(name = "users")
@Entity
class User {
    @Id
    @GeneratedValue
    private Integer id;
    
    private String name;
    private Integer age;
    private ZonedDateTime birthDate;
    private Boolean active;

    // standard getters and setters
}

Let’s also define a repository.

我们也来定义一个资源库。

It’ll extend JpaRepository, one of the Spring Data Repository types:

它将扩展JpaRepository,这是Spring Data Repository类型之一

interface UserRepository extends JpaRepository<User, Integer> {}

This is where we’ll place all our derived query methods.

这就是我们要放置所有派生查询方法的地方。

4. Equality Condition Keywords

4.平等条件的关键词

Exact equality is one of the most-used conditions in queries. We have several options to express = or IS operators in the query.

完全平等是查询中最常用的条件之一。我们有几种选择来表达查询中的=或IS运算符。

We can just append the property name without any keyword for an exact match condition:

我们可以只附加属性名称,而不附加任何关键字,以达到完全匹配的条件。

List<User> findByName(String name);

And we can add Is or Equals for readability:

而且我们可以添加IsEquals,以提高可读性。

List<User> findByNameIs(String name);
List<User> findByNameEquals(String name);

This extra readability comes in handy when we need to express inequality instead:

当我们需要表达不等式时,这种额外的可读性就很方便了。

List<User> findByNameIsNot(String name);

This is quite a bit more readable than findByNameNot(String)!

这比findByNameNot(String)更有可读性!

As null equality is a special case, we shouldn’t use the = operator. Spring Data JPA handles null parameters by default. So, when we pass a null value for an equality condition, Spring interprets the query as IS NULL in the generated SQL.

由于null平等是一种特殊情况,我们不应该使用=操作符。Spring Data JPA 默认处理null参数。因此,当我们为平等条件传递一个null值时,Spring会在生成的SQL中将查询解释为IS NULL。

We can also use the IsNull keyword to add IS NULL criteria to the query:

我们还可以使用IsNull关键字来向查询添加IS NULL条件。

List<User> findByNameIsNull();
List<User> findByNameIsNotNull();

Note that neither IsNull nor IsNotNull requires a method argument.

注意,无论是IsNull还是IsNotNull都不需要一个方法参数。

There are also two more keywords that don’t require any arguments.

另外还有两个不需要任何参数的关键词。

We can use True and False keywords to add equality conditions for boolean types:

我们可以使用TrueFalse关键字来为boolean类型添加平等条件。

List<User> findByActiveTrue();
List<User> findByActiveFalse();

Of course, we sometimes want something more lenient than exact equality, so let’s see what else we can do.

当然,我们有时想要比完全平等更宽松的东西,所以让我们看看我们还能做什么。

5. Similarity Condition Keywords

5.相似性条件关键词

When we need to query the results with a pattern of a property, we have a few options.

当我们需要用一个属性的模式来查询结果时,我们有几个选择。

We can find names that start with a value using StartingWith:

我们可以使用StartingWith找到以一个值开始的名字。

List<User> findByNameStartingWith(String prefix);

Roughly, this translates to “WHERE name LIKE ‘value%’“.

粗略地说,这翻译成 “WHERE name LIKE ‘value%’“。

If we want names that end with a value, EndingWith is what we want:

如果我们想要以一个值结束的名字,EndingWith就是我们想要的。

List<User> findByNameEndingWith(String suffix);

Or we can find which names contain a value with Containing:

或者我们可以用Containing找到哪些名字包含一个值。

List<User> findByNameContaining(String infix);

Note that all conditions above are called predefined pattern expressions. So, we don’t need to add operator inside the argument when these methods are called.

请注意,上述所有条件都被称为预定义模式表达式。所以,当这些方法被调用时,我们不需要在参数里面添加%操作符

But let’s suppose we are doing something more complex. Say we need to fetch the users whose names start with an a, contain b and end with c.

但让我们假设我们正在做一些更复杂的事情。假设我们需要获取名字以a开头,包含bc结尾的用户。

For that, we can add our own LIKE with the Like keyword:

为此,我们可以用Like关键词添加我们自己的LIKE。

List<User> findByNameLike(String likePattern);

And we can then hand in our LIKE pattern when we call the method:

然后我们就可以在调用方法时交出我们的LIKE模式。

String likePattern = "a%b%c";
userRepository.findByNameLike(likePattern);

That’s enough about names for now. Let’s try some other values in User.

关于名字,现在已经够了。让我们试试User中的一些其他值。

6. Comparison Condition Keywords

6.比较条件关键词

Furthermore, we can use LessThan and LessThanEqual keywords to compare the records with the given value using the < and <= operators:

此外,我们可以使用LessThanLessThanEqual关键字,使用<<=操作器,将记录与给定值进行比较。

List<User> findByAgeLessThan(Integer age);
List<User> findByAgeLessThanEqual(Integer age);

In the opposite situation, we can use GreaterThan and GreaterThanEqual keywords:

在相反的情况下,我们可以使用GreaterThanGreaterThanEqual关键词。

List<User> findByAgeGreaterThan(Integer age);
List<User> findByAgeGreaterThanEqual(Integer age);

Or we can find users who are between two ages with Between:

或者我们可以用Between找到介于两个年龄段的用户。

List<User> findByAgeBetween(Integer startAge, Integer endAge);

We can also supply a collection of ages to match against using In:

我们还可以使用In提供一个年龄集合来进行匹配。

List<User> findByAgeIn(Collection<Integer> ages);

Since we know the users’ birthdates, we might want to query for users who were born before or after a given date.

由于我们知道用户的出生日期,我们可能想查询在某个特定日期之前或之后出生的用户。

We’d use Before and After for that:

我们会用BeforeAfter来做这个。

List<User> findByBirthDateAfter(ZonedDateTime birthDate);
List<User> findByBirthDateBefore(ZonedDateTime birthDate);

7. Multiple Condition Expressions

7.多重条件表达式

We can combine as many expressions as we need by using And and Or keywords:

我们可以通过使用AndOr关键字来组合我们需要的表达式。

List<User> findByNameOrBirthDate(String name, ZonedDateTime birthDate);
List<User> findByNameOrBirthDateAndActive(String name, ZonedDateTime birthDate, Boolean active);

The precedence order is And then Or, just like Java.

优先顺序是And 然后Or,就像Java。

While Spring Data JPA imposes no limit to how many expressions we can add, we shouldn’t go crazy here. Long names are unreadable and hard to maintain. For complex queries, take a look at the @Query annotation instead.

虽然Spring Data JPA对我们可以添加的表达式数量没有限制,但我们不应该在这里发疯。长长的名字让人看不懂,而且难以维护。对于复杂的查询,请看看@Query注释。

8. Sorting the Results

8.对结果进行分类

Next, let’s look at sorting.

接下来,让我们来看看排序问题。

We could ask that the users be sorted alphabetically by their name using OrderBy:

我们可以要求使用OrderBy将用户按姓名的字母顺序排序。

List<User> findByNameOrderByName(String name);
List<User> findByNameOrderByNameAsc(String name);

Ascending order is the default sorting option, but we can use Desc instead to sort them in reverse:

升序是默认的排序选项,但我们可以使用Desc代替,对它们进行反向排序。

List<User> findByNameOrderByNameDesc(String name);

9. findOne vs findById in a CrudRepository

9.findOnefindByIdCrudRepository中的比较

The Spring team made some major changes in CrudRepository with Spring Boot 2.x. One of them is renaming findOne to findById.

Spring团队在CrudRepository中对Spring Boot 2.x做了一些重大改变,其中之一是将findOne改名为findById

Previously with Spring Boot 1.x, we’d call findOne when we wanted to retrieve an entity by its primary key:

以前在Spring Boot 1.x中,当我们想通过主键来检索一个实体时,我们会调用findOne

User user = userRepository.findOne(1);

Since Spring Boot 2.x, we can do the same with findById:

从Spring Boot 2.x开始,我们可以用findById进行同样的操作。

User user = userRepository.findById(1);

Note that the findById() method is already defined in CrudRepository for us. So, we don’t have to define it explicitly in custom repositories that extend CrudRepository.

注意,findById()方法已经在CrudRepository中为我们定义了。所以,我们不需要在扩展CrudRepository的自定义仓库中明确定义它。

10. Conclusion

10.结语

In this article, we explained the query derivation mechanism in Spring Data JPA. We used the property condition keywords to write derived query methods in Spring Data JPA repositories.

在这篇文章中,我们解释了Spring Data JPA中的查询衍生机制。我们使用属性条件关键字来编写Spring Data JPA资源库中的衍生查询方法。

The source code of this article is available in the GitHub project.

本文的源代码可在GitHub项目中找到。