JPA CriteriaQuery按最新子项属性排序

时间:2015-01-18 10:04:05

标签: java jpa criteria-api

我有两个实体: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

1 个答案:

答案 0 :(得分:3)

我不是回答我自己的问题的粉丝,但我找到了解决方案。希望它能帮助别人。

我的错是在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);