构建JPA Criteria API查询 - 按集合中的元素数排序

Vla*_*mir 5 java orm hibernate jpa jpql

我在使用JPA Criteria API构建查询时遇到问题.

实体和重要财产:

@Entity
public class Post {
    @Id int id;
    @OneToMany (mappedBy = "post") Set<Comment> comments;
    //...
}

@Entity
public class Comment {
    @Id int id;
    @ManyToOne Post post;
    //...
}
Run Code Online (Sandbox Code Playgroud)

我需要一个查询,它将返回按照注释数量(OneToManyin Post)排序的db中的所有帖子.起初我认为这可以用以下方式实现JPQL:

SELECT p 
FROM Post p 
ORDER BY SIZE(p.comments) DESC
Run Code Online (Sandbox Code Playgroud)

但功能SIZE(...)不能用它来订购JPQL.

所以,我找到了JPA Criteria API,并尝试了以下内容:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Post> cq = cb.createQuery(Post.class);
Root<Post> p = cq.from(Post.class);
cq.select(p);
cq.orderBy(cb.desc(p.get("comments")));
List<Post> resultList = em.createQuery(cq).getResultList();
Run Code Online (Sandbox Code Playgroud)

有了这个查询,我没有得到正确的结果.我知道我错过size了设置'评论',但不知道如何添加该部分.我不是很熟悉JPA Criteria API.这个查询应该如何通过其comments字段(集合)的大小来查找所有帖子?

Mar*_*son 6

CriteriaBuilder.size(Expression)返回Expression<Integer>您可以在ORDER BY子句中使用的.这行代码:

p.get("comments")
Run Code Online (Sandbox Code Playgroud)

..returns a Path<X>扩展,Expression<X>因此使用返回的值作为Collection.size()的参数是安全的.

但是,之前引用的代码行使用了Path.get()的特定重载版本,这将使编译器无法推断类型参数X.相反,将假定类型参数为Object. Collection.size()已宣布他的表情参数是一个"参数化类型"与"上限"的Collection(这不是在第一参考准确地反映到CriteriaBuilder.size()在我的答案,StackOverflow上坚持擦除方法签名中的类型.请参阅JavaDocs!).所以我们必须明确提供类型参数.

试试这个:

cq.orderBy(cb.desc(cb.size(p.<Collection>get("comments"))));
Run Code Online (Sandbox Code Playgroud)