子选择以使用CriteriaBuilderJPA检索语句的右侧

问题描述

| 我正在玩JPA和其他Java EE 6东西,但是现在我在使用条件构建器进行类型查询时遇到了一些问题。 我的poc的业务案例是一个Twitter克隆,因此我有一些用户,其中包含订阅者和订阅列表,并且获得了Tweets。
@Entity
public class Tweet {
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    @ManyToOne
    private TwitterUser author;

    @ManyToOne
    private TwitterUser receiver;

    @Temporal(TemporalType.TIMESTAMP) 
    private Date datetime; 

    private String message;
}


@Entity
public class TwitterUser {
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    private String username;

    private String displayname;

    private String password;

    private String email;

    @Temporal(TemporalType.TIMESTAMP)
    private Date since;

    @ManyToMany(cascade=CascadeType.ALL)
    private List<TwitterUser> subscriptions;

    @ManyToMany(mappedBy = \"subscriptions\")
    private List<TwitterUser> subscribers;
}
JPA生成的数据模型包括3个表:Tweet,TwitterUser和TwitterUser_TwitterUser。到目前为止一切都很好。基本查询效果很好。 现在,我想为时间线选择所有推文,这意味着当前登录用户订阅列表中的所有用户推文。我想到了使用subselect的解决方案,因此我的sql如下所示:
select * from TWEET where author_id in (
    select subscriptions_ID from TWITTERUSER_TWITTERUSER where subscribers_ID = ?loggedInUserId);
查询工作良好,但我不知道如何使用CriteriaBuilder和泛型将其记录下来。我什至没有得到可能在其他时候失败的可编译代码,因为我不确定子查询的类型。 我现在正在搜索大量示例,但是它们大多只是使用原始类型或使用子查询来检索子句左侧的元素。 也许我想念那些树木,但是我在这里真的很困惑。 :(     

解决方法

        在JPQL中,一种表达方式类似于以下内容:
SELECT
    tweet
FROM
    Tweet tweet JOIN tweet.author author
WHERE
    EXISTS (
        SELECT 
               user 
         FROM 
                TwitterUser user JOIN user.subscriptions subscriber
         WHERE 
                user = :loggedinUser AND
                subscriber = author
    )
由于Criterias几乎直接遵循JPQL模型,因此这可能会让您入门。     ,        因此,再次感谢你们对我的帮助。我终于设法用您的输入找到了一个解决方案,它看起来如下:
public List<Tweet> findAllForSubscriber(TwitterUser user) {
    // Select tweets
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Tweet> cq = cb.createQuery(Tweet.class);
    Root<Tweet> tweet = cq.from(Tweet.class);
    cq.select(Tweet);

    // Select subscribers of user
    Subquery<Long> sq = cq.subquery(Long.class);
    Root<TwitterUser> twitterUser = sq.from(TwitterUser.class);
    Join<TwitterUser,TwitterUser> subscriptions = twitterUser.join(TwitterUser_.subscriptions);
    sq.select(subscriptions.get(TwitterUser_.id));
    sq.where(cb.equal(twitterUser,user));

    // Where authorId in list of subscribers
    cq.where(cb.in(tweet.get(Tweet_.author).get(TwitterUser_.id)).value(sq));

    //
    return em.createQuery(cq).getResultList();
}
我的缺点是: Criteria API只是能够 比较对象中的对象 equal()但不在in()内 声明。但是我没有得到 有用的例外 生成的是错误的查询(eclipselink和derby):( in()语句 取入的左侧 语句,值语句需要 可能性列表 措辞使我困惑。 我不能简单地访问ID 在所有订阅中,我必须使用 加入。如果你想的话很清楚 关于表结构,但我 只是在想到时就错过了 我的对象。 附注:我的解决方案完全错过了选择用户本人的推文的机会! ^^     ,        这里有一个类似的条件查询示例, http://en.wikibooks.org/wiki/Java_Persistence/Querying#Subselect.2C_querying_all_of_a_ManyToMany_relationship