此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Data Redis 3.4.5

按示例查询

介绍

本章介绍了 Query by Example 并说明了如何使用它。

Example Query by Example (QBE) 是一种用户友好的查询技术,具有简单的界面。 它允许创建动态查询,并且不需要您编写包含字段名称的查询。 事实上,Query by Example 根本不要求您使用特定于商店的查询语言编写查询。

本章介绍了 Query by Example 的核心概念。 该信息是从 Spring Data Commons 模块中提取的。 根据您的数据库,字符串匹配支持可能会受到限制。

用法

Query by Example API 由四个部分组成:

  • 探测:具有填充字段的域对象的实际示例。

  • ExampleMatcher:这ExampleMatcher包含有关如何匹配特定字段的详细信息。 它可以在多个 Example 中重复使用。

  • Example:一Example由 probe 和ExampleMatcher. 它用于创建查询。

  • FetchableFluentQuery:一个FetchableFluentQuery提供 Fluent API,允许进一步自定义从Example. 使用 Fluent API 可以为查询指定排序、投影和结果处理。

Query by Example 非常适合以下几种使用案例:

Query by Example 也有几个限制:

  • 不支持嵌套或分组属性约束,例如firstname = ?0 or (firstname = ?1 and lastname = ?2).

  • 特定于 Store 的字符串匹配支持。 根据您的数据库,字符串匹配可以支持字符串的 starts/contains/ends/regex。

  • 其他属性类型的精确匹配。

在开始使用 Query by Example 之前,您需要有一个域对象。 要开始使用,请为您的仓库创建一个界面,如以下示例所示:

Sample Person 对象
public class Person {

  @Id
  private String id;
  private String firstname;
  private String lastname;
  private Address address;

  // … getters and setters omitted
}

前面的示例显示了一个简单的域对象。 您可以使用它来创建一个Example. 默认情况下,具有null值将被忽略,并使用特定于 Store 的默认值匹配字符串。

将属性包含在 Query by Example 条件中基于可为 null 性。 使用基元类型 (int,double, …)始终包含在内,除非ExampleMatcher忽略属性路径.

示例可以通过使用offactory 方法或使用ExampleMatcher.Example是不可变的。 下面的清单显示了一个简单的示例:

示例 1.简单示例
Person person = new Person();                         (1)
person.setFirstname("Dave");                          (2)

Example<Person> example = Example.of(person);         (3)
1 创建 domain 对象的新实例。
2 设置要查询的属性。
3 创建Example.

您可以使用存储库运行示例查询。 为此,请让您的仓库接口扩展QueryByExampleExecutor<T>. 下面的清单显示了QueryByExampleExecutor接口:

QueryByExampleExecutor
public interface QueryByExampleExecutor<T> {

  <S extends T> S findOne(Example<S> example);

  <S extends T> Iterable<S> findAll(Example<S> example);

  // … more functionality omitted.
}

示例 Matchers

示例不限于默认设置。 您可以使用ExampleMatcher,如以下示例所示:

示例 2.具有自定义匹配的示例 matcher
Person person = new Person();                          (1)
person.setFirstname("Dave");                           (2)

ExampleMatcher matcher = ExampleMatcher.matching()     (3)
  .withIgnorePaths("lastname")                         (4)
  .withIncludeNullValues()                             (5)
  .withStringMatcher(StringMatcher.ENDING);            (6)

Example<Person> example = Example.of(person, matcher); (7)
1 创建 domain 对象的新实例。
2 设置属性。
3 创建一个ExampleMatcher以期望所有值都匹配。 即使无需进一步配置,它也可以在此阶段使用。
4 构造一个新的ExampleMatcher忽略lastnameproperty path 的
5 构造一个新的ExampleMatcher忽略lastname属性路径并包含 null 值。
6 构造一个新的ExampleMatcher忽略lastname属性路径,以包含 null 值,并执行后缀字符串匹配。
7 新建Example基于域对象和配置的ExampleMatcher.

默认情况下,ExampleMatcher期望 Probe 上设置的所有值都匹配。 如果要获得与隐式定义的任何谓词匹配的结果,请使用ExampleMatcher.matchingAny().

您可以为各个属性指定行为(例如“firstname”和“lastname”,或者对于嵌套属性,则为“address.city”)。 您可以使用匹配选项和区分大小写对其进行优化,如以下示例所示:

配置 matcher 选项
ExampleMatcher matcher = ExampleMatcher.matching()
  .withMatcher("firstname", endsWith())
  .withMatcher("lastname", startsWith().ignoreCase());
}

配置 matcher 选项的另一种方法是使用 lambdas(在 Java 8 中引入)。 此方法创建一个回调,要求实现者修改匹配器。 您无需返回 matcher,因为 configuration 选项保存在 matcher 实例中。 以下示例显示了使用 lambda 的匹配程序:

使用 lambda 配置 matcher 选项
ExampleMatcher matcher = ExampleMatcher.matching()
  .withMatcher("firstname", match -> match.endsWith())
  .withMatcher("firstname", match -> match.startsWith());
}

查询创建者Example使用配置的合并视图。 默认匹配设置可以在ExampleMatcher级别,而单个设置可以应用于特定的属性路径。 设置在ExampleMatcher由属性路径设置继承,除非它们被显式定义。 属性 Patch 上的设置的优先级高于默认设置。 下表描述了各种ExampleMatcher设置:

表 1.范围ExampleMatcher设置
设置 范围

Null 处理

ExampleMatcher

字符串匹配

ExampleMatcher和属性路径

忽略属性

属性路径

区分大小写

ExampleMatcher和属性路径

价值转型

属性路径

Fluent API

QueryByExampleExecutor提供了另一种方法,到目前为止我们没有提到:<S extends T, R> R findBy(Example<S> example, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction). 与其他方法一样,它执行从Example. 但是,使用第二个参数,您可以控制该执行的方面,否则您将无法动态控制这些方面。 您可以通过调用FetchableFluentQuery在第二个参数中。sortBy用于指定结果的顺序。as用于指定要将结果转换为的类型。project限制查询的属性。first,firstValue,one,oneValue,all,page,stream,countexists定义您获得的结果类型以及当可用结果数超过预期数量时查询的行为方式。

使用 Fluent API 获取可能许多结果中的最后一个结果,按 lastname 排序。
Optional<Person> match = repository.findBy(example,
    q -> q
        .sortBy(Sort.by("lastname").descending())
        .first()
);

运行示例

以下示例对存储库使用 Query by Example:

例 3.使用存储库按示例查询
interface PersonRepository extends ListQueryByExampleExecutor<Person> {
}

class PersonService {

  @Autowired PersonRepository personRepository;

  List<Person> findPeople(Person probe) {
    return personRepository.findAll(Example.of(probe));
  }
}

Redis 存储库及其二级索引支持 Spring Data 的 Query by Example 功能的子集。 特别是,仅使用精确、区分大小写和非 null 值来构造查询。

二级索引使用基于集的作 (Set intersection, Set union) 来确定匹配的键。向未编制索引的查询添加属性不会返回任何结果,因为不存在索引。Query by Example 支持检查索引配置,以仅包含索引涵盖的查询中的属性。这是为了防止意外包含非索引属性。

不区分大小写的查询和不支持的查询StringMatcher实例在运行时被拒绝。

以下列表显示了支持的 Query by Example 选项:

以下列表显示了 Query by Example 不支持的属性:


APP信息