1. 概述

在Spring Data中,通过方法名派生查询是常见操作。当处理实体间关系(如嵌套对象)时,Spring Data提供了多种机制来检索嵌套对象的数据。

本文将探讨如何使用查询派生JPQL(Java持久化查询语言),通过嵌套对象的属性进行查询。

2. 场景说明

考虑一个简单场景:两个实体CustomerOrder,每个Order通过@ManyToOne关联到Customer

我们的目标是:查找属于特定邮箱地址的客户的所有订单。这里emailCustomer的属性,而主查询在Order实体上执行。

示例实体如下:

@Entity
@Table(name = "customers")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String email;

   // getters and setters
}

@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;

   // getters and setters
}

3. 使用查询派生

Spring Data JPA通过从Repository接口的方法签名派生查询简化了查询创建:

3.1 常规场景

若要通过关联Customeremail查找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 关键字冲突场景

⚠️ 踩坑警告:假设Order类中除了嵌套的Customer对象,还有一个名为customerEmail的字段。此时Spring Data JPA不会按预期生成关联查询:

select
    o.id,
    o.customer_id,
    o.customer_email,
    o.order_date
from
    orders o
where
    o.customer_email = ?

解决方案:用下划线明确分隔关键字

List<Order> findByCustomer_Email(String email);

下划线能帮助Spring Data JPA正确解析查询方法。

4. 使用JPQL查询

当需要更精细控制查询逻辑或执行复杂操作时,JPQL是更好的选择。通过JPQL按Customeremail查询Order

@Query("SELECT o FROM Order o WHERE o.customer.email = ?1")
List<Order> findByCustomerEmailAndJPQL(String email);

这种方式摆脱了方法名约定的限制,提供更灵活的查询定制能力。

5. 总结

本文探讨了在Spring Data中通过嵌套对象属性查询数据的两种方式:

  • 查询派生:简单场景下直接通过方法名实现
  • JPQL查询:复杂场景下提供更灵活的控制

掌握这些技术,可以轻松应对大多数嵌套对象查询需求。


原始标题:Find by Property of a Nested Object in Spring Data | Baeldung