Spring Data JPA:CriteriaQuery 获取每个唯一外键具有最大值的实体

Ole*_*lov 5 sql hibernate jpa criteria-api spring-data-jpa

有一个Event类:

@Entity
public class Event {

    @Id
    private Integer id;

    @ManyToOne(cascade = CascadeType.ALL)
    private Company company;

    @Column
    private Long time;

    ...

}
Run Code Online (Sandbox Code Playgroud)

我想要一个EventFilter类(实现Specification),它将CriteriaQuery以与以下 SQL 查询相同的方式生成选择实体:

SELECT *
FROM events e1
WHERE e1.time = (
    SELECT MAX(time)
    FROM events e2
    WHERE e1.company_id = c2.company_id
)
Run Code Online (Sandbox Code Playgroud)

筛选结果将仅包含每个公司具有唯一值Company和最大值的事件。time

这是EventFilter我最终得到的课程:

public class EventFilter implements Specification<Event> {

    @Override
    public Predicate toPredicate(Root<Event> root, CriteriaQuery<?> q, CriteriaBuilder cb) {
        Subquery<Long> subquery = q.subquery(Long.class);
        Root<Event> subRoot = subquery.from(Event.class);
        subquery.select(cb.max(root.get("time")))
                .where(cb.equal(root.get("company"), subRoot.get("company")));
        return cb.equal(root.get("time"), subquery);
    }

}
Run Code Online (Sandbox Code Playgroud)

调用时EventRepository#findAll(EventFilter filter),结果根本不会被过滤。请帮助我正确地实现这个逻辑。

Ole*_*lov 4

在检查 Hibernate 生成的 SQL 语句后,我发现了一个错误:rootwasused 而不是subRoot. 正确的方法体是:

Subquery<Long> sub = q.subquery(Long.class);     
Root<Event> subRoot = sub.from(Event.class);     
sub.select(cb.max(subRoot.get("time")))
   .where(cb.equal(root.get("company"), subRoot.get("company")));
return cb.equal(root.get("time"), sub);
Run Code Online (Sandbox Code Playgroud)