2011-09-13 2 views
2

J'utilise QueryDSL avec JPA.QueryDSL: interrogation des relations et propriétés

Je veux interroger certaines propriétés d'une entité, il est comme ça:

QPost post = QPost.post; 
JPAQuery q = new JPAQuery(em); 
List<Object[]> rows = q.from(post).where(...).list(post.id, post.name); 

Il fonctionne très bien.

Si je veux interroger une propriété de relation, par ex. commentaires d'un article:

List<Set<Comment>> rows = q.from(post).where(...).list(post.comments); 

C'est aussi bien.

Mais quand je veux interroger la relation et les propriétés simples ensemble, par ex. Puis, quelque chose s'est mal passé, générant une mauvaise syntaxe SQL.

Puis j'ai réalisé qu'il n'est pas possible de les interroger ensemble dans une instruction SQL.

Est-il possible que QueryDSL traiterait en quelque sorte les relations et générer des requêtes supplémentaires (tout comme ce que fait avec mise en veille prolongée relations paresseux), et charger les résultats en?

Ou devrais-je simplement demander deux fois, puis fusionner les deux listes de résultats?

P.S. ce que je veux réellement, c'est chaque message avec les ids de ses commentaires. Donc, une fonction pour concaténer les identifiants des commentaires de chaque publication est meilleure, est-ce que ce genre d'expression est possible?

q.list(post.id, post.name, post.comments.all().id.join()) 

et générer un sql comme sous-requête (select group_concat(c.id) from comments as c inner join post where c.id = post.id)

Répondre

5

Querydsl JPA est limitée à l'expressivité de JPQL, donc ce que vous demandez est impossible avec Querydsl JPA. Vous pouvez cependant essayer de l'exprimer avec Querydsl SQL. Cela devrait être possible. De même que vous ne projetez pas les entités, mais les littéraux et les collections, cela peut très bien fonctionner.

Sinon, vous pouvez charger les messages avec seulement le commentaire ids chargés et projeter l'identifiant, le nom et commenter ids à autre chose. Cela devrait fonctionner lorsque les accesseurs sont annotés.

+0

Merci pour la réponse. Je ne comprends pas bien ... dans la méthode SQL, vouliez-vous dire que je peux appeler la sous-requête dans SQL QueryDSL? dans ce dernier cas, vouliez-vous dire que je devrais avoir une propriété distincte de la liste commentIds (avec une formule dessus)? –

+0

Vous pouvez utiliser des sous-requêtes avec QueryDSl SQL, oui. Et concernant votre deuxième question, non, juste la propriété normale, mais paresseusement récupérée, avec des propriétés annotées, vous pouvez accéder à la propriété id, mais sans aller chercher l'objet entier. –

+0

Merci! Je ne connaissais pas l'effet d'annotation de l'accesseur avant. Je vais regarder dans cela :) –

3

La chose la plus simple serait d'interroger des messages et utiliser fetchJoin des commentaires, mais je suppose que c'est trop lent pour que vous utilisez le cas.

Je pense que vous devez projeter simplement les propriétés requises des messages et des commentaires et regrouper les résultats à la main (le cas échéant). Par exemple.

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)); 
} 

REMARQUE: Vous ne pouvez pas utiliser de limite ou de décalage avec ce type de requête. Comme alternative, il peut être possible de régler vos mappages afin que 1) Les commentaires soient toujours des proxies paresseux afin que (avec l'accès aux propriétés) Comment.getId() soit possible sans initialiser l'objet réel et 2) en utilisant le chargement par lots * sur Post.comments pour optimiser la récupération des collections. De cette façon, vous pouvez simplement effectuer une requête pour les messages, puis accéder aux identifiants de leurs commentaires avec un faible impact sur les performances. Dans la plupart des cas, vous n'avez même pas besoin de ces proxies paresseux à moins que votre commentaire ne soit très gros. Ce type de code aurait certainement l'air plus agréable sans manipulation de ligne de bas niveau et vous pourriez également utiliser la limite et l'offset dans vos requêtes. Gardez un oeil sur votre journal de requête pour vous assurer que tout fonctionne comme prévu.*) La récupération par lots n'est pas directement prise en charge par JPA, mais Hibernate la prend en charge via le mappage et Eclipselink via des indicateurs de requête.

Peut-être que certains Querydsl jour appuieront ce genre de résultats de regroupement post-traitement hors-box ...

+0

La première solution ressemble vraiment aux analyseurs d'Anorm de Playframework :) Vous obtenez ce que les colonnes intéressées, puis analyser/extraire/combiner/aplatir le résultat. J'espère vraiment que Querydsl aurait cette out-of-box ... –

+1

Comment ça sonne: https://bugs.launchpad.net/querydsl/+bug/849735? –

Questions connexes