此版本仍在开发中,尚未被视为稳定版本。如需最新稳定版本,请使用 Spring Data Cassandra 5.0.4spring-doc.cadn.net.cn

属性路径

本章介绍属性路径(property paths)的概念。 属性路径是一种通过领域类进行导航的方式,用于在与模型交互的上下文中应用特定功能。 应用程序代码向数据访问组件提供属性路径,以表达诸如查询中选择属性、构建谓词或应用排序等意图。 属性路径起始于其所属类型,并可包含一个或多个段(segments)。spring-doc.cadn.net.cn

遵循领域驱动设计(Domain-Driven Design)原则,构成持久化领域模型核心并通过 Spring Data 访问的类被称为实体(entity)。 对象图的入口点称为聚合根(aggregate root)。spring-doc.cadn.net.cn

了解如何导航和引用这些属性对于使用仓库和查询操作至关重要。spring-doc.cadn.net.cn

属性路径概述

属性路径提供了一种简单的、基于文本的机制,用于导航领域模型的属性。 本节介绍属性路径导航的基础知识,并展示基于字符串方法与类型安全方法之间的权衡。spring-doc.cadn.net.cn

领域模型示例
class Person {
  String firstname, lastname;
  int age;
  Address address;
  List<Address> previousAddresses;

  String getFirstname() { … } // other property accessors omitted for brevity

}

class Address {
  String city, street;

  // accessors omitted for brevity

}
class Person {
  var firstname: String? = null
  var lastname: String? = null
  var age: Int = 0
  var address: Address? = null
  var previousAddresses: List<Address> = emptyList()
}

class Address {
  var city: String? = null
  var street: String? = null
}

属性路径使用点号表示法(dot-notation)在整个 Spring Data 操作(例如排序和过滤)中表达属性引用:spring-doc.cadn.net.cn

点号表示法属性引用
Sort.by("firstname", "address.city")

属性路径由一个或多个以点(.)分隔的段组成。 除非另有说明,接受属性路径的方法支持单段引用(顶层属性)和多段导航。spring-doc.cadn.net.cn

集合和数组属性支持透明地遍历到其组件类型,从而可以直接引用嵌套属性:spring-doc.cadn.net.cn

Sort.by("address.city")             (1)

Sort.by("previousAddresses")        (2)

Sort.by("previousAddresses.city")   (3)
1 从顶层的 address 属性导航到 city 字段。
2 引用整个 previousAddresses 集合(某些技术在基于集合的排序中支持此操作)。
3 遍历集合,按每个地址的 city 字段进行排序。

基于字符串的属性路径提供了简洁性,并且可以广泛使用,但也有需要权衡的方面:spring-doc.cadn.net.cn

  • 灵活性:属性路径具有灵活性,可以从常量字符串、配置或用户输入的结果中构建。spring-doc.cadn.net.cn

  • 非类型化:字符串路径不携带编译时类型信息。 作为文本内容进行类型化,它们不依赖于底层的领域类型。spring-doc.cadn.net.cn

  • 重构风险:重命名领域属性通常需要手动更新字符串字面量;IDE 无法可靠地追踪这些引用。spring-doc.cadn.net.cn

为了提高重构的安全性和类型一致性,建议使用方法引用的方式创建类型安全的属性引用。 这种方法将属性路径与编译时的类型信息关联起来,并支持编译器验证和 IDE 驱动的重构。 详情请参见类型安全的属性引用spring-doc.cadn.net.cn

有关实现细节,请参阅属性路径内部机制以获取更多信息。

属性路径内部机制

org.springframework.data.core 包是 Spring Data 在领域类之间进行导航的基础。 TypeInformation 接口提供类型内省功能,能够解析属性的类型。PropertyPath 表示通过领域类的文本导航路径。spring-doc.cadn.net.cn

它们共同提供:spring-doc.cadn.net.cn

类型安全的属性引用

类型安全的属性引用消除了数据访问代码中一个常见的错误来源:脆弱的、基于字符串的属性引用。 本节说明如何使用方法引用来表达在重构时安全的属性路径。spring-doc.cadn.net.cn

虽然属性路径是对象导航的简单表示,但基于字符串的属性路径在重构过程中本质上很脆弱,因为随着属性定义与其使用之间距离的增加,它们很容易被遗漏。 通过 TypedPropertyPath 提供的类型安全替代方案可以从方法引用中派生属性路径,使编译器能够验证属性名称,并使 IDE 支持重构操作。spring-doc.cadn.net.cn

// Inline usage with Sort
Sort.by(Person::getFirstName, Person::getLastName);

// Composed navigation
Sort.by(TypedPropertyPath.of(Person::getAddress).then(Address::getCity),
            Person::getLastName);
// Inline usage with Sort
Sort.by(Person::firstName, Person::lastName)

// Composed navigation
Sort.by(Person::address / Address::city, Person::lastName)

类型安全的属性路径与查询抽象和条件构建器无缝集成,使得可以在不使用基于字符串的属性引用的情况下,以声明式方式构建查询。spring-doc.cadn.net.cn

采用类型安全的属性引用符合现代 Spring 开发原则。 通过提供声明式、类型安全且流畅的 API,结合 IDE 的重构支持以及编译器对无效属性的早期反馈,可以简化对数据访问逻辑的理解,并彻底消除一类潜在的 bug。spring-doc.cadn.net.cn

为提高效率,Lambda 表达式的内省结果会被缓存,以支持重复使用。 JVM 会重用静态的 Lambda 实例,从而将一次性解析带来的开销降至最低。spring-doc.cadn.net.cn

如果你正在寻找一种类型安全的变体,并且希望在不直接集成 Spring Data API 的场景中获得编译器验证和 IDE 支持,你可以单独使用 TypedPropertyPathspring-doc.cadn.net.cn

import static org.springframework.data.core.TypedPropertyPath.path;

// Static import variant
path(Person::getAddress)
                 .then(Address::getCity);

// Fluent composition
TypedPropertyPath.of(Person::getAddress)
                 .then(Address::getCity);
// Kotlin API
TypedPropertyPath.of(Person::address / Address::city)

// as extension function
(Person::address / Address::city).toPath()

类型安全的属性引用 API 建议

在使用(或构建)基于类型安全的属性引用的 API 时,请考虑以下建议:spring-doc.cadn.net.cn

  • 使用方法引用:接受方法引用(例如 Person::getFirstName),而不是字符串,以利用编译时验证和 IDE 的重构支持。 方法引用更受推荐,因为它们在 Java 和 Kotlin 中具有相似的表示形式。 此外,由于方法引用的表示形式更简单,与 Lambda 表达式相比,它们提供了更好的性能基准。spring-doc.cadn.net.cn

  • 利用 T 类型的 TypedPropertyPath: 每当接受类型化的属性路径时,请考虑使用泛型类型T of TypedPropertyPath<T, P>. 将属性路径限制为当前操作中使用的特定域类型,可减少使用其他类型中非预期属性的风险。

    每当接受或提供多个属性路径时,请考虑使用TypedPropertyPath<T, ?>以允许在拥有类型的上下文中使用属性T将属性路径限制为共同的拥有类型。spring-doc.cadn.net.cn

Graal 原生镜像编译需要可序列化的 TypedPropertyPath Lambda 表达式的可达性元数据。 Spring Data 通过 org.springframework.data.core.TypedPropertyPathFeature 内置了功能。 该功能会自动激活,并为 Lambda 解析及相关的反射成员(字段和方法)注册所需的序列化和反射元数据。 请注意,当使用 Lambda 表达式而非方法引用时,您需要在原生镜像配置中自行包含包含该 Lambda 表达式的类的 Java 源代码。