QueryDSL:查询关系和属性

时间:2011-09-13 06:46:09

标签: jpa querydsl

我正在使用带有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)

2 个答案:

答案 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会支持这种结果分组后处理开箱即用...