在 JPA Criteria API 之上构建更简洁的投影层

发布: (2026年1月12日 GMT+8 22:37)
3 min read
原文: Dev.to

Source: Dev.to

介绍

如果你使用 Java 和 JPA 开发系统,可能已经遇到过只需要返回给定实体的部分属性的查询需求。
乍一看这似乎很简单,但如果处理不当,系统可能会累积不必要的查询,或出现包含永远不会使用的属性的查询。

在许多真实场景中,开发者只需要获取实体的 idname。由于系统规模和复杂度,往往难以判断是否已经存在返回恰好这些数据的查询。还有的情况下,开发者会重复使用加载整个实体的方法,随后再提取实际需要的少量属性。

ProjectionQuery 的创建旨在简化和组织基于投影的查询,提供一种更清晰、更具表达力的方式,只选择应用真正需要的数据。

定义投影

在项目中添加依赖后,创建一个类(或 record),并为需要投影的字段加上注解。

@Projection(of = Customer.class)
public record CustomerBasicData(
        @ProjectionField Long id,
        @ProjectionField String name,
        @ProjectionField("address.city.name") String city,
        @ProjectionField("address.city.state.name") String state
) { }

该 record 表示查询结果的最终结构。无论 Customer 实体中有多少属性,只有 idnamecitystate 会从数据库中被选取。
需要注意的是,citystate 是通过 Customer 实体中定义的关系获取的嵌套属性。

生成的 SQL(简化)

上述投影对应的 SQL 大致如下:

SELECT
    c.id,
    c.name,
    city.name   AS city,
    state.name  AS state
FROM customer c
INNER JOIN address a   ON c.address = a.id
INNER JOIN city   ci  ON a.city = ci.id
INNER JOIN state  s   ON ci.state = s.id;

执行投影

简化执行

ProjectionProcessor processor = new ProjectionProcessor(entityManager);
List customers = processor.execute(CustomerBasicData.class);

在高级场景中使用 ProjectionQuery

ProjectionQuery 帮助构建更复杂的查询,支持添加过滤、排序、分页以及其他配置。

ProjectionProcessor processor = new ProjectionProcessor(entityManager);

ProjectionQuery query = ProjectionQuery
    .fromTo(Customer.class, CustomerBasicData.class)
    .filter("address.city.name", ProjectionFilterOperator.EQUAL, "São Paulo")
    .order("name", OrderDirection.ASC)
    .paging(0, 20)
    .distinct();

List customers = processor.execute(query);

ProjectionQuery 可以独立使用,也可以集成到 Spring Boot 应用中。

更多资源

欲了解更多细节、示例以及完整文档,请访问 GitHub 上的项目页面。

Back to Blog

相关文章

阅读更多 »

我直到构建持久层才明白 JPA

封面图片 👉“I Didn’t Understand JPA Until I Built the Persistence Layer” https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto...

懒加载 vs. 急加载 & JPA 关系

!Forem 徽标https://media2.dev.to/dynamic/image/width=65,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2...

Spring Data JPA 关系

介绍 新年快乐!在我 full‑stack 之旅的过去十天里,我在加入后立刻开始着手项目。起初,我在 Re...