Установите флажок, чтобы получить правую часть входного оператора с помощью CriteriaBuilder (JPA) - PullRequest
2 голосов
/ 12 июня 2011

Я играю с JPA и другими вещами Java EE 6, но теперь я столкнулся с некоторыми проблемами с запросом типов, использующим построитель критериев.Бизнес-кейс для моего документа - клон Twitter, поэтому у меня есть пользователи, у которых есть список подписчиков и подписок, и я получил твиты.

@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.Пока все хорошо.Базовые запросы работают хорошо.

Теперь я хочу выбрать все твиты для временной шкалы, что означает все твиты пользователей, которые находятся в списке подписок текущего вошедшего в систему пользователя.Я подумал о решении с использованием подвыбора, поэтому мой sql будет выглядеть так:

select * from TWEET where author_id in (
    select subscriptions_ID from TWITTERUSER_TWITTERUSER where subscribers_ID = ?loggedInUserId);

Этот запрос работает хорошо, но я не знаю, как записать его с помощью CriteriaBuilder и обобщений.Я даже не получаю скомпилируемый кусок кода, который может потерпеть неудачу в какой-то другой момент, потому что я не уверен, каким должен быть тип подзапроса.Я искал много примеров сейчас, но они в основном просто используют raw-типы или используют подзапрос для извлечения элемента левой части предложения.

Может быть, я скучаю по дереву для деревьевно я действительно озадачен здесь.(

Ответы [ 3 ]

3 голосов
/ 13 июня 2011

В 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
    )

Поскольку критерии следуют модели JPQL почти напрямую, возможно, это поможет вам начать работу.

1 голос
/ 14 июня 2011

Итак, еще раз спасибо вам, ребята, помогаете мне.Мне, наконец, удалось найти решение с вашим вводом, и оно выглядит следующим образом:

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 просто способен сравнивать объектыв пределах равенства (), но не в выражении in ().Но я не получил полезного исключения, все, что было сгенерировано, было неправильным запросом (eclipselink & derby): (
  • Оператор in () занимает левую часть оператора in, оператор value принимаетсписок возможностей, формулировка смутила меня.
  • Я не могу просто получить доступ ко всем идентификаторам всех подписок, мне нужно использовать объединение. Совершенно ясно, если вы думаете о структуре таблицы, но я упустил это, когда просто подумалмои объекты.

PS: Мое решение совершенно не позволяет выбрать твиты самого пользователя! ^^

0 голосов
/ 13 июня 2011

Здесь есть похожий пример запроса Criteria,

http://en.wikibooks.org/wiki/Java_Persistence/Querying#Subselect.2C_querying_all_of_a_ManyToMany_relationship

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...