You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否通过Spring Data Projection实现跨两层@OneToMany关联的JPA查询映射至DTO?

跨两层@OneToMany关联的JPA查询结果映射至DTO(Spring Data Projection实现)

完全可行,结合Spring Data Projection与JPQL聚合查询即可实现需求,以下是具体方案:

1. 定义目标DTO(Projection接口)

使用Spring Data的接口式Projection,无需编写实现类,框架会自动生成动态代理:

public interface BirdDetailsDto {
    String getName();
    String getSex();
    Double getLatestAvgLength();
}

2. 编写Repository查询方法

通过JPQL实现关联查询、筛选最新HealthCheck、聚合计算平均值,直接映射到DTO:

@Repository
public interface BirdRepository extends JpaRepository<Bird, Long> {
    @Query("""
        SELECT b.name AS name, 
               b.sex AS sex, 
               AVG(lm.value) AS latestAvgLength
        FROM Bird b
        LEFT JOIN b.healthChecks hc
        LEFT JOIN hc.lengthMeasurements lm
        WHERE hc.checkDateTime = (
            SELECT MAX(hc2.checkDateTime)
            FROM HealthCheck hc2
            WHERE hc2.bird = b
        )
        GROUP BY b.id, b.name, b.sex
    """)
    List<BirdDetailsDto> findAllBirdDetails();
}

关键说明:

  • 子查询用于筛选每个Bird对应的最新HealthCheck(基于checkDateTime最大值)
  • 通过LEFT JOIN确保即使Bird无HealthCheck或HealthCheck无LengthMeasurements时仍能返回结果(此时latestAvgLength为null)
  • 因HealthCheck继承自Task,只要Task中定义的lengthMeasurements关联映射正确,JPQL可直接通过hc.lengthMeasurements访问

3. 可选:类形式DTO

若需要更灵活的逻辑(比如默认值处理),可改用类形式DTO,需提供匹配的构造方法:

public record BirdDetailsDto(String name, String sex, Double latestAvgLength) {
    // 可选:添加带默认值的构造方法,处理null场景
    public BirdDetailsDto(String name, String sex) {
        this(name, sex, 0.0);
    }
}

此时JPQL需调整为调用构造方法:

@Query("""
    SELECT new com.yourpackage.BirdDetailsDto(b.name, b.sex, AVG(lm.value))
    FROM Bird b
    LEFT JOIN b.healthChecks hc
    LEFT JOIN hc.lengthMeasurements lm
    WHERE hc.checkDateTime = (
        SELECT MAX(hc2.checkDateTime)
        FROM HealthCheck hc2
        WHERE hc2.bird = b
    )
    GROUP BY b.id, b.name, b.sex
""")
List<BirdDetailsDto> findAllBirdDetails();

内容的提问来源于stack exchange,提问作者Ray Bond

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:53:12