我正在使用带有JPA的QueryDSL。
我想查询一个实体的某些属性,就像这样:
QPost post = QPost.post;
JPAQuery q = new JPAQuery(em);
List<Object[]> rows = q.from(post).where(...).list(post.id, post.name);
工作正常。
如果我想查询关系属性,例如评论帖子:
List<Set<Comment>> rows = q.from(post).where(...).list(post.comments);
也没关系。
但是当我想要一起查询关系和简单属性时,例如
List<Object[]> rows = q.from(post).where(...).list(post.id, post.name, post.comments);
然后出了问题,产生了错误的SQL语法。
然后我意识到在一个SQL语句中不可能一起查询它们。
QueryDSL是否有可能以某种方式处理关系并生成其他查询(就像hibernate对惰性关系所做的那样),并加载结果?
或者我应该只查询两次,然后合并两个结果列表?
P.S。我真正想要的是每个帖子及其评论'ID。因此,连接每个帖子的评论ID的功能更好,这种表达是否可能?
q.list(post.id, post.name, post.comments.all().id.join())
生成子查询sql,如(select group_concat(c.id) from comments as c inner join post where c.id = post.id)
答案 0 :(得分:5)
Querydsl JPA仅限于JPQL的表现力,因此Querydsl JPA无法满足您的要求。您可以尝试使用Querydsl SQL表达它。它应该是可能的。此外,由于您没有投影实体,但文字和集合可能会正常工作。
或者,您可以仅加载注释ID来加载帖子,然后将id,name和comment id投影到其他内容。当访问者被注释时,这应该有用。
答案 1 :(得分:3)
最简单的方法是查询帖子并使用fetchJoin进行评论,但我认为这对你的用例来说太慢了。
我认为你应该简单地设计帖子和评论所需的属性,并手动分组结果(如果需要)。例如。
QPost post=...;
QComment comment=..;
List<Tuple> rows = q.from(post)
// Or leftJoin if you want also posts without comments
.innerJoin(comment).on(comment.postId.eq(post.id))
.orderBy(post.id) // Could be used to optimize grouping
.list(new QTuple(post.id, post.name, comment.id));
Map<Long, PostWithComments> results=...;
for (Tuple row : rows) {
PostWithComments res = results.get(row.get(post.id));
if (res == null) {
res = new PostWithComments(row.get(post.id), row.get(post.name));
results.put(res.getPostId(), res);
}
res.addCommentId(row.get(comment.id));
}
注意:您不能对此类查询使用限制或偏移。
作为替代方案,可以调整映射以便1)注释始终是惰性代理,以便(具有属性访问权限)可以在不初始化实际对象的情况下使用Comment.getId()和2)使用批量提取*在Post.comments上优化收集提取。通过这种方式,您只需查询帖子,然后访问其评论的ID,几乎没有性能损失。在大多数情况下,除非你的评论很胖,否则你甚至不需要那些懒惰的代理。如果没有低级别的行处理,那种代码肯定看起来更好,你也可以在查询中使用限制和偏移量。只需密切关注查询日志,确保一切正常。
*)JPA不直接支持批量提取,但Hibernate通过映射和Eclipselink通过查询提示支持它。
也许有一天Querydsl会支持这种结果分组后处理开箱即用...