Como escrevo esta consulta jpql?
Pergunta
Diga que tenho 5 mesas,
tblBlogs tblBlogPosts tblBlogPostComment tblUser tblBlogMember
BlogId BlogPostsId BlogPostCommentId UserId BlogMemberId
BlogTitle BlogId CommentText FirstName UserId
PostTitle BlogPostsId BlogId
BlogMemberId
Agora, quero recuperar apenas os blogs e postagens para os quais o membro do blog realmente comentou. Então, em suma, como escrevo este velho sql antigo?
SELECT b.BlogTitle, bp.PostTitle, bpc.CommentText FROM tblBlogs b
INNER JOIN tblBlogPosts bp on b.BlogId = bp.BlogId
INNER JOIN tblBlogPostComment bpc on bp.BlogPostsId = bpc.BlogPostsId
INNER JOIN tblBlogMember bm ON bpc.BlogMemberId = bm.BlogMemberId
WHERE bm.UserId = 1;
Como você pode ver, tudo é interno, então apenas essa linha será recuperada para a qual o usuário comentou em algum post de algum blog. Portanto, suponha que ele ingressou em três blogs cujos IDs são 1,2,3 (os blogs que o usuário ingressou estão no TblblogMembers), mas o usuário apenas comentou no Blog 2 (do Say BlogPostid = 1). Para que a linha seja recuperada e 1,3 não, pois é a junção interna. Como faço para escrever esse tipo de consulta em JPQL?
No JPQL, só podemos escrever consultas simples como digamos:
Select bm.blogId from tblBlogMember Where bm.UserId = objUser;
Onde o Objuser é fornecido usando:
em.find(User.class,1);
Assim, uma vez que obtemos todos os blogs (aqui o BlogId representa um objeto de blog) que o usuário se uniu, podemos passar e fazer todas as coisas sofisticadas. Mas não quero cair nesse negócio de loop e escrever todas essas coisas no meu código Java. Em vez disso, quero deixar isso para o mecanismo de banco de dados. Então, como escrevo o SQL simples acima no JPQL? E que tipo de objeto a consulta JPQL retornará? Porque estou selecionando apenas alguns campos de todas as tabela. Em que classe devo digitar o resultado?
Acho que postei minha exigência corretamente, se não estiver claro, por favor me avise.
ATUALIZAÇÃO: De acordo com a resposta de Pascal, tentei escrever uma consulta JPQL para a consulta SQL acima. Estou enfrentando um pequeno problema. Esta consulta está funcionando, mas está incompleta:
SELECT bm.blogId FROM BlogMembers bm
INNER JOIN bm.blogId b
INNER JOIN b.blogPostsList bp
INNER JOIN bp.blogPostCommentList bpc
WHERE bm.userId = :userId
Eu quero modificar isso para:
SELECT bm.blogId FROM BlogMembers bm
INNER JOIN bm.blogId b
INNER JOIN b.blogPostsList bp
INNER JOIN bp.blogPostCommentList bpc
WHERE bpc.blogMembersId = bm.blogMembersId AND bm.userId = :userId
A consulta acima não está funcionando. Como posso resolver esse problema?
Solução 2
Ok, esta é a resposta final. Demorou uma hora para enquadrar essa linha. Recebi muitos erros estranhos durante essa hora, mas agora meus conceitos são claros o suficiente:
@NamedQuery(name = "BlogMembers.findBlogsOnWhichCommentsAreMade",
query = "SELECT bm.blogId FROM BlogMembers bm INNER JOIN bm.blogId b
INNER JOIN b.blogPostsList bp INNER JOIN bp.blogPostCommentList bpc
INNER JOIN bpc.blogMembersId bmt WHERE bm.userId = :userId")
Outras dicas
No JPQL, só podemos escrever consultas simples (...)
Isso não é verdade e o JPQL suporta [ LEFT [OUTER] | INNER ] JOIN
. Para junções internas, consulte a seção 4.4.5.1 Juns internos (o relacionamento se junta) da especificação:
4.4.5.1 Juns internos (o relacionamento se junta)
A sintaxe para a operação de junção interna é
[ INNER ] JOIN join_association_path_expression [AS] identification_variable
Por exemplo, a consulta abaixo se junta ao relacionamento entre clientes e pedidos. Esse tipo de junção normalmente equivale a uma junção sobre um relacionamento de chave estrangeira no banco de dados.
SELECT c FROM Customer c JOIN c.orders o WHERE c.status = 1
A palavra -chave interna pode opcionalmente ser usada:
SELECT c FROM Customer c INNER JOIN c.orders o WHERE c.status = 1
Você só precisa pensar em associação entre entidades.