JPA CriteriaQuery Order By Latest Child 属性

JPA CriteriaQuery Order By Latest Child Property

我有 2 个实体:Project 和 ProjectStatus。

项目实体:

@Entity
public class Project {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @OneToMany(mappedBy = "project")
    private List<ProjectStatus> projectStatusses;
}

项目状态实体:

@Entity
public class ProjectStatus {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @ManyToOne
    private Project project;

    @Enumerated(EnumType.STRING)
    private ProjectStatusType statusType;
}

我想通过 CriteriaQuery.orderBy.

按项目的最新状态类型订购项目

我得出以下结论:

CriteriaQuery<Project> criteriaQuery = criteriaBuilder.createQuery(Project.class);
Root<Project> root = criteriaQuery.from(Project.class);
Join<Project, ProjectStatus> join = root.join("projectStatusses", JoinType.LEFT);
criteriaQuery.orderBy(criteriaBuilder.asc(join.get("statusType")));

我希望上面的查询只考虑最新的项目状态,但我不知道该怎么做。 我怎样才能做到这一点?

更新: 实现这个的sql是:

SELECT proj.*, stat.statustype 
FROM project proj
LEFT JOIN projectStatus stat ON proj.id = stat.project_id
WHERE stat.id = (SELECT MAX(id) FROM projectstatus WHERE project_id = proj.id)
ORDER BY stat.statustype

我不喜欢回答我自己的问题,但我找到了解决方案。希望它能对其他人有所帮助。

我的错误是在criteriaQuery.orderBy方法中寻找解决方案。在 criteriaQuery.where 方法中添加一个子查询就可以了。

解法:

    CriteriaQuery<Project> criteriaQuery = criteriaBuilder.createQuery(Project.class);
    Root<Project> root = criteriaQuery.from(Project.class);
    Join<Project, ProjectStatus> join = root.join("projectStatusses", JoinType.LEFT);

    //Create a subquery to get latest ProjectStatus for project
    Subquery sq = criteriaBuilder.createQuery().subquery(Long.class);
    Root<T> from = sq.from(Project.class);
    Path<ProjectStatus> path = root.join("projectStatusses");
    //Get latest status
    sq.select(criteriaBuilder.max(path.<Long>get("id")));
    //For each project
    sq.where(criteriaBuilder.equal(from.<Long>get("id"), root.<Long>get("id")));
    Predicate latestStatusCondition = criteriaBuilder.and(criteriaBuilder.equal(join.get("id"), sq));

    criteriaQuery.orderBy(criteriaBuilder.asc(join.get("statusType")));
    criteriaQuery.where(latestStatusCondition);