乐趣区

关于spring:Spring认证中国教育管理中心Spring-Data-Neo4j教程五

原题目:Spring 认证中国教育管理中心 -Spring Data Neo4j 教程五(Spring 中国教育管理中心)

Spring 认证:Spring Data Neo4j 教程五
7.4. 定义查询方法
存储库代理有两种办法能够从办法名称派生特定于存储的查问:

通过间接从办法名称派生查问。
通过应用手动定义的查问。
可用选项取决于理论商店。然而,必须有一种策略来决定创立什么理论查问。下一节将介绍可用的选项。

7.4.1。查问查找策略
以下策略可用于存储库基础架构来解决查问。应用 XML 配置,您能够通过 query-lookup-strategy 属性在命名空间配置策略。对于 Java 配置,您能够应用注解的 queryLookupStrategy 属性。Enable${store}Repositories 特定数据存储可能不反对某些策略。

CREATE 尝试从查询方法名称结构特定于存储的查问。个别的办法是从办法名称中删除一组给定的已知前缀并解析办法的其余部分。您能够在“第 7.4.2 节”中浏览无关查问结构的更多信息。
USE_DECLARED_QUERY 尝试查找已申明的查问,如果找不到则抛出异样。查问能够由某处的正文定义或通过其余形式申明。请参阅特定商店的文档以查找该商店​的可用选项。如果存储库根底构造在疏导时没有找到该办法的申明查问,它就会失败。
CREATE_IF_NOT_FOUND(默认)联合 CREATE 和 USE_DECLARED_QUERY。它首先查找已申明的查问,如果未找到已申明的查问,则创立一个基于自定义办法名称的查问。这是默认查找策略,因而,如果您未明确配置任何内容,则应用此策略。它容许通过办法名称疾速定义查问,还能够通过依据须要引入申明的查问来自定义调整这些查问。
7.4.2. 查问创立
Spring Data 存储库根底构造中内置的查问构建器机制对于在存储库的实体上构建束缚查问很有用。

以下示例显示了如何创立多个查问:

示例 23. 从办法名称创立查问

interface PersonRepository extends Repository<Person, Long> {

List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

// Enables the distinct flag for the query
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

// Enabling ignoring case for an individual property
List<Person> findByLastnameIgnoreCase(String lastname);
// Enabling ignoring case for all suitable properties
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

// Enabling static ORDER BY for a query
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}
解析查询方法名称分为主语和谓语。第一局部 (find…By, exists…By) 定义查问的主题,第二局部形成谓词。引言从句(主语)能够蕴含进一步的表白。find(或其余介绍关键字)和之间的任何文本 By 都被认为是描述性的,除非应用后果限度关键字之一,例如在 Distinct 要创立的查问上设置不同的标记或 Top/First 来限度查问后果。

附录蕴含查询方法主题关键字和查询方法谓词关键字的残缺列表,包含排序和字母大小写修饰符。然而,第一个 By 用作分隔符以批示理论条件谓词的开始。在十分根本的级别上,您能够在实体属性上定义条件并将它们与 And 和连接起来 Or。

解析办法的理论后果取决于您为其创立查问的持久性存储。然而,有一些个别的事件须要留神:

表达式通常是联合了能够连贯的运算符的属性遍历。您能够将属性表达式与 AND 和联合应用 OR。您还能够取得对运算符(如 Between、LessThan、和)的反对 GreaterThan,以及 Like 对属性表达式的反对。反对的运算符可能因数据存储而异,因而请参阅参考文档的相应局部。
办法解析器反对 IgnoreCase 为单个属性(例如,findByLastnameIgnoreCase(…))或反对疏忽大小写的类型的所有属性(通常是 String 实例 – 例如,findByLastnameAndFirstnameAllIgnoreCase(…))设置标记。是否反对疏忽大小写可能因商店而异,因而请参阅参考文档中的相干局部以理解商店特定的查询方法。
您能够通过将子句附加 OrderBy 到援用属性的查询方法并提供排序方向(Asc 或 Desc)来利用动态排序。要创立反对动静排序的查询方法,请参阅“第 7.4.4 节”。
7.4.3. 属性表达式
属性表达式只能援用托管实体的间接属性,如后面的示例所示。在创立查问时,您曾经确保解析的属性是托管域类的属性。然而,您也能够通过遍历嵌套属性来定义束缚。思考以下办法签名:

List<Person> findByAddressZipCode(ZipCode zipCode);
假如 aPerson 有 Address 一个 ZipCode。在这种状况下,该办法会创立 x.address.zipCode 属性遍历。解析算法首先将整个局部 (AddressZipCode) 解释为属性,并查看域类中具备该名称(未大写)的属性。如果算法胜利,它将应用该属性。如果不是,该算法将源在驼峰局部从右侧拆分为头部和尾部,并尝试找到相应的属性——在咱们的示例中,AddressZip 和 Code。如果算法找到具备该头部的属性,它将获取尾部并持续从那里向下构建树,以方才形容的形式将尾部拆分。如果第一个宰割不匹配,算法将宰割点向左挪动 (Address,ZipCode) 并持续。

尽管这应该实用于大多数状况,但算法可能会抉择谬误的属性。假如这个 Person 类也有一个 addressZip 属性。该算法曾经在第一个拆分轮中匹配,抉择了谬误的属性,而后失败(因为 的类型 addressZip 可能没有 code 属性)。

要解决这种歧义,您能够_在办法名称中应用手动定义遍历点。所以咱们的办法名称如下:

List<Person> findByAddress_ZipCode(ZipCode zipCode);
因为咱们将下划线字符视为保留字符,咱们强烈建议遵循规范的 Java 命名约定(即,不在属性名称中应用下划线,而是应用驼峰式大小写)。

7.4.4. 非凡参数解决
要解决查问中的参数,请定义后面示例中曾经看到的办法参数。除此之外,该基础架构还能够辨认某些特定类型,例如 Pageableand Sort,以便动静地将分页和排序利用于您的查问。以下示例演示了这些性能:

示例 24. 在查询方法中应用 Pageable、、Slice 和 Sort

Page<User> findByLastname(String lastname, Pageable pageable);

Slice<User> findByLastname(String lastname, Pageable pageable);

List<User> findByLastname(String lastname, Sort sort);

List<User> findByLastname(String lastname, Pageable pageable);
API 承受 Sort 并 Pageable 冀望将非 null 值传递给办法。如果您不想利用任何排序或分页,请应用 Sort.unsorted()and Pageable.unpaged()。

第一种办法容许您将
org.springframework.data.domain.Pageable 实例传递给查询方法,以动静地将分页增加到动态定义的查问中。APage 晓得可用元素和页面的总数。它通过基础设施触发计数查问来计算总数来实现这一点。因为这可能很低廉(取决于应用的商店),您能够改为返回 Slice. ASlice 只晓得下一个 Slice 是否可用,这在遍历更大的后果集时可能就足够了。

排序选项也通过 Pageable 实例解决。如果您只须要排序,
org.springframework.data.domain.Sort 请在您的办法中增加一个参数。如您所见,返回 aList 也是可能的。在这种状况下,不会创立构建理论实例所需的额定元数据 Page(这反过来意味着不会收回原本须要的额定计数查问)。相同,它将查问限度为仅查找给定范畴的实体。

要理解整个查问取得了多少页,您必须触发额定的计数查问。默认状况下,此查问派生自您理论触发的查问。

分页和排序
您能够应用属性名称定义简略的排序表达式。您能够连贯表达式以将多个条件收集到一个表达式中。

示例 25. 定义排序表达式

Sort sort = Sort.by(“firstname”).ascending()
.and(Sort.by(“lastname”).descending());
要应用更平安的形式来定义排序表达式,请从要为其定义排序表达式的类型开始,并应用办法援用来定义要排序的属性。

示例 26. 应用类型平安 API 定义排序表达式

TypedSort<Person> person = Sort.sort(Person.class);

Sort sort = person.by(Person::getFirstname).ascending()
.and(person.by(Person::getLastname).descending());
TypedSort.by(…) 通过(通常)应用 CGlib 来应用运行时代理,这可能会在应用 Graal VM Native 等工具时烦扰本机映像编译。

如果您的商店实现反对 Querydsl,您还能够应用生成的元模型类型来定义排序表达式:

示例 27. 应用 Querydsl API 定义排序表达式

QSort sort = QSort.by(QPerson.firstname.asc())
.and(QSort.by(QPerson.lastname.desc()));
7.4.5 限度查问后果
first 您能够应用 or 关键字来限度查询方法的后果 top,您能够调换应用它们。您能够将可选数值附加到 top 或 first 指定要返回的最大后果大小。如果省略该数字,则假设后果大小为 1。以下示例显示了如何限度查问大小:

Top 示例 28. 应用 and 限度查问的后果大小 First

User findFirstByOrderByLastnameAsc();

User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

Slice<User> findTop3ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);

List<User> findTop10ByLastname(String lastname, Pageable pageable);
限度表达式还反对 Distinct 反对不同查问的数据存储的关键字。Optional 此外,对于将后果集限度为一个实例的查问,反对应用关键字将后果包装到其中。

如果分页或切片利用于限度查问分页(以及可用页数的计算),则在限度后果中利用。

通过应用参数限度后果与动静排序相结合,Sort 您能够表白“K”最小元素和“K”最大元素的查询方法。

7.4.6 返回汇合或迭代的存储库办法
返回多个后果的查询方法能够应用规范的 Java Iterable、List 和 Set. 除此之外,咱们还反对返回 Spring Data 的 Streamable 自定义扩大 Iterable,以及 Vavr 提供的汇合类型。请参阅解释所有可能的查询方法返回类型的附录。

应用 Streamable 作为查询方法返回类型
您能够 Streamable 用作任何汇合类型的替代品 Iterable 或任何汇合类型。它提供了不便的办法来拜访非并行 Stream(短少 Iterable)以及间接….filter(…)和….map(…)笼罩元素并将其连贯 Streamable 到其余元素的能力:

示例 29. 应用 Streamable 组合查询方法后果

interface PersonRepository extends Repository<Person, Long> {
Streamable<Person> findByFirstnameContaining(String firstname);
Streamable<Person> findByLastnameContaining(String lastname);
}

Streamable<Person> result = repository.findByFirstnameContaining(“av”)
.and(repository.findByLastnameContaining(“ea”));
返回自定义 Streamable Wrapper 类型
为汇合提供专用的包装器类型是为返回多个元素的查问后果提供 API 的罕用模式。通常,通过调用返回相似汇合类型的存储库办法并手动创立包装器类型的实例来应用这些类型。您能够防止该额定步骤,因为 Spring Data 容许您将这些包装器类型用作查询方法返回类型,如果它们满足以下条件:

类型实现 Streamable.
该类型公开了一个构造函数或一个名为 of(…)或作为参数的动态工厂办法。valueOf(…)Streamable
以下清单显示了一个示例:

class Product {
MonetaryAmount getPrice() { …}
}

@RequiredArgsConstructor(staticName = “of”)
class Products implements Streamable<Product> {

private final Streamable<Product> streamable;

public MonetaryAmount getTotal() {

return streamable.stream()
  .map(Priced::getPrice)
  .reduce(Money.of(0), MonetaryAmount::add);

}

@Override
public Iterator<Product> iterator() {

return streamable.iterator();

}
}

interface ProductRepository implements Repository<Product, Long> {
Products findAllByDescriptionContaining(String text);
}
公开 API 以拜访产品价格的 Product 实体。

Streamable<Product> 能够通过应用 Products.of(…)(应用 Lombok 正文创立的工厂办法)结构的包装器类型。采纳意志的规范构造函数 Streamable<Product> 也能够。

包装器类型公开了一个额定的 API,用于计算 Streamable<Product>.

实现 Streamable 接口并委托给理论后果。

该包装器类型 Products 能够间接用作查询方法返回类型。您不须要 Streamable<Product> 在存储库客户端中的查问之后返回并手动包装它。

Spring 认证:Spring Data Neo4j 教程五
反对 Vavr 汇合
Vavr 是一个蕴含 Java 函数式编程概念的库。它附带一组自定义汇合类型,您能够将其用作查询方法返回类型,如下表所示:

Spring 认证:Spring Data Neo4j 教程五
您能够将第一列(或其子类型)中的类型用作查询方法返回类型,并依据理论查问后果的 Java 类型(第三列)获取第二列中用作实现类型的类型。或者,您能够申明 Traversable(VavrIterable 等效项),而后咱们从理论返回值派生实现类。也就是说,ajava.util.List 变成 VavrList 或 Seq,ajava.util.Set 变成 Vavr LinkedHashSet Set,依此类推。

退出移动版