Spring Boot 3.1.2 子选择查询失败 - Hibernate 6.2

问题描述 投票:0回答:1

我希望能够在 Spring Boot 3.1.2 中使用本机 Hibernate 查询。其原因是,据我了解,HQL 可以比 JPQL 更好地处理嵌套 SELECT(而不是在 where 中)。

我的型号是 Bird 在 HealthCheck 上有 OneToMany HealthCheck 在任务上有 OneToMany(摘要) 长度测量(扩展任务) 体重测量(扩展任务)

public class Bird {
private Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "bird")
private List<HealthCheck> listHealthCheck = new ArrayList<>();

健康检查

public class HealthCheck {
private Long id;

@JsonManagedReference
@ManyToOne(fetch = FetchType.EAGER, optional = false)
private Bird bird;
@JsonManagedReference
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy="healthCheck")
private List<Task> tasks;
private LocalDateTime catchDateTime;

长度测量

public class LengthMeasurements extends Task {

private Double beakLength;
private Double legLength;
private Double armWidth;
private Double armDepth;

体重测量

public class WeightMeasurements extends Task {
    private Double weight;

抽象类Task意味着我不能使用hibernate路径表达式。

我想最终构建一个查询,获取最近测量集合的最新(基于检查日期)平均值和最新权重的平均值。

类似:

+---------+-----------+---------------------+------------+-----------+-----------+--------------------+------------+
| bird.id | bird.name | recent measure date | avg length | avg width | avg depth | recent weight date | avg weight |
+---------+-----------+---------------------+------------+-----------+-----------+--------------------+------------+

有许多部分示例,但它们很旧,并且 Spring Boot 自动配置干扰了我迄今为止尝试过的内容。

为了提供迄今为止我的尝试的一些背景信息,我有以下代码:

@Repository
public class CustomBirdRepositoryImpl {

@PersistenceContext
private EntityManager entityManager;


    final SessionFactory sf = entityManager
            .unwrap( Session.class );

    public void customHql(Long id) {
    Session session = sf.openSession();

    String hql = " SELECT MAX(h.catchDateTime), AVG(l.beakLength), 
AVG(l.tarsusLength),  AVG(l.tarsusWidth), b.name FROM LengthMeasurements l 
 JOIN l.healthCheck.bird b 
 JOIN l.healthCheck h 
 LEFT JOIN (SELECT MAX(w.healthCheck.catchDateTIme), AVG(w.weight), w.healthCheck.bird.id as bid FROM WeightMeasurements w WHERE w.healthCheck.bird.id=1) AS x
 ON x.bid = w.healthCheck.bird.id
 WHERE b.id=1 GROUP BY b.id, h.id ORDER BY l.healthCheck.catchDateTime DESC LIMIT 1";
    org.hibernate.query.Query<BirdDetailsDto> query = session.createQuery(hql);

    for(BirdDetailsDto b: query.getResultList()) {
        b.toString();
    }

   }
}

如果我尝试在 JPA 中运行上面的查询,我会得到:

  src\main\java\com\nz\kiwi\repository\BirdRepository.java:54: error: ')' expected
    "WHERE b.id = :id ORDER BY l.healthCheck.catchDate DESC LIMIT 1) lm";)

更新

在 Hibernate 会话中尝试查询时,我收到了信息更丰富的错误:

Caused by: java.lang.IllegalArgumentException: Component at index 0 has no alias, but alias is required

如何执行这个子选择语句?

java hibernate jpa jpql
1个回答
0
投票

事实证明,hibernate 6 中的内部

SELECT
语句是相对较新的功能。

虽然内部

SELECT
可以单独工作,但在
LEFT JOIN
中使用时,值需要别名。

所以这个片段:

SELECT MAX(w.healthCheck.catchDateTime), AVG(w.weight)
变成
SELECT MAX(w.healthCheck.catchDateTime) AS weight_date, AVG(w.weight) AS avg_weight

把它们放在一起:

@Service
@Transactional
public class CustomBirdRepositoryImpl implements CustomBirdRepository {

@PersistenceContext
private EntityManager entityManager;

@Override
public Object customQuery(Long id) {
    return entityManager.createQuery(
                    "SELECT MAX(h.catchDateTime), AVG(l.beakLength), AVG(l.tarsusLength),  AVG(l.tarsusWidth), b.name, b.id, weight_date, avg_weight FROM LengthMeasurements l " +
                            "JOIN l.healthCheck h " +
                            "JOIN h.bird b " +
                            "LEFT JOIN(SELECT MAX(w.healthCheck.catchDateTime) AS weight_date, AVG(w.weight) AS avg_weight, w.healthCheck.bird.id as bid FROM WeightMeasurements w WHERE w.healthCheck.bird.id=:id) AS x " +
                            "ON b.id = x.bid " +
                            "WHERE b.id=:id " +
                            "GROUP BY b.id, h.id ORDER BY l.healthCheck.catchDateTime DESC LIMIT 1")
            .setParameter("id", id)
            .getSingleResult();
    }
}

为了完整性 CustomBirdRepository

@Repository
public interface CustomBirdRepository {
    Object customQuery(Long id);
}
© www.soinside.com 2019 - 2024. All rights reserved.