1、概览 {#1概览}
在 Spring Data 中,使用基于方法名称的派生查询来查询实体是很常见的。在处理实体之间的关系(如嵌套对象)时,Spring Data 提供了各种机制来检索这些嵌套对象中的数据。
本文将带你了解如何使用查询派生和 JPQL(Java 持久性查询语言)通过嵌套对象的属性进行查询。
2、场景概述 {#2场景概述}
考虑一个有两个实体的简单场景:Customer
和 Order
。每个 Order
都通过 ManyToOne
(多对一)关系关联到一个 Customer
。
我们要查找属于某个 Customer
的所有 Order
,该 Customer
有特定的 email
。在这种情况下,email
是 Customer
实体的属性,而我们的主要查询将在 Order
实体上执行。
实体示例如下:
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// Getter / Setter 省略
}
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Date orderDate;
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
// Getter / Setter 省略
}
3、使用派生查询 {#3使用派生查询}
Spring Data JPA 允许开发者从 Repository
接口中的方法签名派生查询,从而简化了查询创建:
3.1、常规使用案例 {#31常规使用案例}
在一般情况下,如果我们想通过相关 Customer
的 email
查找 Order
实体,我们可以简单地这样做:
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByCustomerEmail(String email);
}
生成的 SQL 如下:
select
o.id,
o.customer_id,
o.order_date
from
orders o
left outer join
customers c
on o.customer_id = c.id
where
c.email = ?
3.2、关键字冲突的情况 {#32关键字冲突的情况}
现在,假设除了嵌套的 Customer
对象外,我们还在 Order
类中设置了一个名为 customerEmail
的字段。在这种情况下,Spring Data JPA 不会像我们期望的那样只在 customers
表中生成查询:
select
o.id,
o.customer_id,
o.customer_email,
o.order_date
from
orders o
where
o.customer_email = ?
在这种情况下,我们可以使用 下划线字符 来定义 JPA 应尝试分割关键字的位置:
List<Order> findByCustomer_Email(String email);
如上,下划线有助于 Spring Data JPA 正确解析查询方法。
4、使用 JPQL 查询 {#4使用-jpql-查询}
如果我们想对查询逻辑进行更多控制或执行更复杂的操作,JPQL 是一个不错的选择。要使用 JPQL 按 Customer
的 email
查询 Order
,我们可以这样写
@Query("SELECT o FROM Order o WHERE o.customer.email = ?1")
List<Order> findByCustomerEmailAndJPQL(String email);
这样,我们就可以灵活地编写更有针对性的查询,而不必依赖方法名称约定。
5、总结 {#5总结}
本文介绍了如何通过 Spring Data 中嵌套对象的属性来查询数据,主要介绍了派生查询和自定义 JPQL 查询的场景下的用法。
Ref:https://www.baeldung.com/spring-data-find-by-property-nested-object