2011-09-13 10 views
2

JPAでQueryDSLを使用しています。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構文が生成されました。

次に、1つのSQLステートメントでそれらを一緒に照会することができないことに気付きました。

QueryDSLがリレーションを扱い、追加のクエリを生成する可能性はありますか(ちょうどhibernateがレイジーリレーションと同じように)?

2回クエリしてから両方の結果リストをマージする必要がありますか?

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)

答えて

5

ようQuerydsl JPAはJPQLの表現力に制限するので、何を求めていることはQuerydsl JPAでは不可能です。あなたはQuerydsl SQLでそれを表現しようとすることもできます。それは可能でなければならない。また、エンティティをプロジェクトするのではなく、リテラルやコレクションを作成するとうまくいくかもしれません。

また、コメントidsだけをロードしてポストを読み込んだ後、ID、名前、およびコメントIDを別のものに投影することもできます。これは、アクセサにアノテートされているときに機能します。

+0

お返事ありがとうございます。私はかなりそれを取得しない... SQLメソッドでは、私はQueryDSL SQLでサブクエリを呼び出すことができますか?後者の場合、リストのcommentIds(数式付き)という別のプロパティを持つ必要がありますか? –

+0

Querydsl SQLでサブクエリを使用できます。あなたの2番目の質問については、いいえ、通常のプロパティだけですが、lazilyフェッチされたアノテーション付きプロパティでは、オブジェクト全体をフェッチせずにidプロパティにアクセスできます。 –

+0

ありがとう!以前はアクセサーアノテーションの効果についてはわかりませんでした。私はそれを調べます:) –

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こうすることで、Postsのクエリを実行して、パフォーマンスの低下がほとんどなく、コメントのIDにアクセスできます。あなたのコメントが非常に肥満でない限り、ほとんどの場合、それらの怠惰なプロキシは必要ありません。この種のコードは、低レベルのロー・ハンドリングがなければより良く見えるでしょうし、あなたのクエリでは限界とオフセットを使うこともできます。クエリログに注目して、すべてが意図どおりに機能することを確認してください。

*)バッチフェッチはJPAで直接サポートされていませんが、Hibernateはクエリーヒントを使ってマッピングとEclipselinkでサポートしています。

多分、Querydslはこの種の結果グループ化アウト・オブ・ボックス処理をサポートします...

+0

最初の解決策は、PlayframeworkのAnormパーサに本当に似ています:)あなたは何列目に興味を持って、次に解析/抽出/結合/結果を平坦化します。私は本当にQuerydslがすぐに使えると思っています。 –

+1

どうしたらいいですか:https://bugs.launchpad.net/querydsl/+bug/849735? –

関連する問題