QueryDSL: запрос отношений и свойств - PullRequest
2 голосов
/ 13 сентября 2011

Я использую QueryDSL с JPA.

Я хочу запросить некоторые свойства объекта, это выглядит так:

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. что я на самом деле хочу, так это каждый пост с его комментариями. Так что лучше использовать функцию, чтобы объединить идентификаторы комментариев каждого поста, возможна ли такая экспрессия?

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 ]

5 голосов
/ 13 сентября 2011

Querydsl JPA ограничен выразительностью JPQL, поэтому то, что вы просите, невозможно с Querydsl JPA.Вы можете попытаться выразить это с помощью Querydsl SQL.Это должно быть возможно.Кроме того, поскольку вы не проецируете сущности, но литералы и коллекции, это может работать просто отлично.

В качестве альтернативы вы можете загружать сообщения только с загруженными идентификаторами комментариев, а затем проецировать идентификаторы, имена и комментарии на что-то другое.,Это должно работать, когда аннотаторы доступа.

3 голосов
/ 13 сентября 2011

Самым простым было бы запросить сообщения и использовать 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, чтобы оптимизировать выборку коллекции. Таким образом, вы можете просто запросить сообщения и затем получить доступ к идентификаторам их комментариев с небольшим снижением производительности. В большинстве случаев вам даже не нужны эти ленивые прокси, если ваш комментарий не очень толстый. Такой код наверняка выглядел бы лучше без обработки строк низкого уровня, и вы также можете использовать ограничения и смещения в ваших запросах. Просто следите за журналом запросов, чтобы убедиться, что все работает, как задумано.

*) Пакетная выборка напрямую не поддерживается JPA, но Hibernate поддерживает ее посредством сопоставления и Eclipselink через подсказки запросов.

Может быть, когда-нибудь Querydsl будет поддерживать этот вид группировки результатов пост-обработки из коробки ...

...