我该如何编写这个JPQL查询?

8

假设我有5个表格,

tblBlogs     tblBlogPosts     tblBlogPostComment    tblUser    tblBlogMember
BlogId        BlogPostsId       BlogPostCommentId   UserId      BlogMemberId
BlogTitle     BlogId            CommentText         FirstName   UserId
              PostTitle         BlogPostsId                     BlogId
                                 BlogMemberId

现在我想仅检索那些blogMember实际上已经评论过的博客和帖子。简而言之,我该如何编写这个普通的SQL?
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;

如您所见,所有的连接都是内部连接,因此只有用户在某个博客的某篇文章上发表评论时才会检索到该行。假设他/她加入了3个id为1、2、3的博客(用户加入的博客在tblBlogMembers中),但用户只在博客2(例如BlogPostId=1)中发表了评论。那么将检索到该行,而1、3则不会出现,因为它是内部连接。我该如何在JPQL中编写这种类型的查询?
在JPQL中,我们只能编写简单的查询,比如说:
Select bm.blogId from tblBlogMember Where bm.UserId = objUser;

objUser是使用以下方式提供的:

em.find(User.class,1);

因此,一旦我们获取了用户加入的所有博客(这里blogId表示博客对象),我们就可以循环并执行所有花哨的操作。但是,我不想陷入这个循环业务中并在我的Java代码中编写所有这些内容。相反,我希望将其留给数据库引擎处理。那么,我该如何将上述普通SQL编写为JPQL?JPQL查询将返回什么类型的对象?因为我只从所有表中选择了几个字段。在哪个类中应该对结果进行类型转换?
如果我没有表达清楚,请告诉我。
更新:根据Pascal的答案,我尝试编写上述SQL查询的JPQL查询。我遇到了一点问题。这个查询是有效的,但是不完整:
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

我想将其修改为:

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

上述查询不起作用。我该如何解决这个问题?
2个回答

17
在JPQL中,我们只能编写简单查询语句(...)这种说法是不正确的。JPQL实际上支持[ LEFT [OUTER] | INNER ] JOIN。对于内连接,请参考规范的4.4.5.1 Inner Joins (Relationship Joins)部分:

4.4.5.1 内连接(关系连接)

内连接操作的语法如下:

[ INNER ] JOIN join_association_path_expression [AS] identification_variable
例如,下面的查询使用客户和订单之间的关系联接。这种类型的联接通常等同于在数据库中通过外键关系进行联接。

例如,下面的查询结合了客户和订单之间的关系。这种类型的连接通常相当于在数据库中连接外键关系。

SELECT c FROM Customer c JOIN c.orders o WHERE c.status = 1

关键字INNER是可选的:

SELECT c FROM Customer c INNER JOIN c.orders o WHERE c.status = 1
你只需要考虑实体之间的关联。

我们如何将以下查询转换为: SELECT productCode, productName, textDescription FROM products INNER JOIN productlines USING (productline); - PAA

10

好的,这是最终答案了。花费了一个小时才构思出这一行代码。在这个小时内我遇到了许多奇怪的错误,但现在我的概念已经足够清晰:

@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")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接