JPA Criteria加入OneToMany表where子句不起作用

时间:2016-12-29 11:55:52

标签: java spring hibernate jpa-2.0

我有两张桌子。

CREATE TABLE public.question
(
    id       SERIAL PRIMARY KEY
  , day      VARCHAR(2)        NOT NULL
  , month    VARCHAR(2)        NOT NULL
  , year     VARCHAR(4)         NOT NULL
);

CREATE TABLE public.question_translation
(
    id SERIAL PRIMARY KEY
  , question_id   INT REFERENCES public.question(id) NOT NULL
  , question_text TEXT                               NOT NULL
  , language      VARCHAR(2)                         NOT NULL
);

现在我想创建检索问题的标准。像这样的SQL:

SELECT * FROM question q LEFT JOIN question_translation qt ON q.id = qt.question_id WHERE qt.language = 'en'

在使用JPA Criterias的java中,它看起来像这样:

@Override
public Collection<Question> findByMonthYear(String month, String year, String locale) {
    EntityManager em = sessionFactory.createEntityManager();
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Question> criteriaQuery = builder.createQuery(Question.class);

    List<Predicate> predicates = new ArrayList<>();

    Root<Question> questionRoot = criteriaQuery.from(Question.class);
    ListJoin<Question, QuestionTranslation> questionTranslationJoinRoot = questionRoot.join(Question_.questionTranslation, JoinType.LEFT);

    predicates.add(builder.equal(questionRoot.get(Question_.month), month));
    predicates.add(builder.equal(questionRoot.get(Question_.year), year));
    predicates.add(builder.equal(questionTranslationJoinRoot.get(QuestionTranslation_.language), locale));

    criteriaQuery.select(questionRoot).where(predicates.toArray(new Predicate[]{}));

    TypedQuery<Question> query = em.createQuery(criteriaQuery);

    String queryString = query.unwrap(Query.class).getQueryString();

    return query.getResultList();
}

我使用ListJoin,因为在元模型Question_.class中我得到了这一行:

public static volatile ListAttribute<Question, QuestionTranslation> questionTranslation;

但是这个给我带有List QuestionTranslation的Question类,其中有两个条目,其中语言字段等于ende值。但我指定where子句只返回一个语言等于en值的条目。我的代码出了什么问题?

更新#1:

我有第二个案例。

还有一张表:

CREATE TABLE public.user_answer
(
    uuid        VARCHAR(36) PRIMARY KEY
  , user_uuid   VARCHAR(36) REFERENCES public.users(uuid)  NOT NULL
  , question_id INT         REFERENCES public.question(id) NOT NULL
  , answer      TEXT                                       NOT NULL
);

我想像这样制作SQL:

SELECT * FROM user_answer ua LEFT JOIN question q on ua.question_id = q.id LEFT JOIN question_translation qt ON q.id = qt.question_id WHERE qt.language = 'en' AND ua.user_uuid = '00000000-user-0000-0000-000000000001' AND q.month = '01' AND q.day = '01' AND q.year = '2016';

在使用JPA Criterias的java中,它看起来像这样:

@Override
public UserAnswer findByDayMonthYear(String day, String month, String year, User user, String locale) {
    EntityManager em = sessionFactory.createEntityManager();
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<UserAnswer> criteriaQuery = builder.createQuery(UserAnswer.class);

    List<Predicate> predicates = new ArrayList<>();

    Root<UserAnswer> userAnswerRoot = criteriaQuery.from(UserAnswer.class);
    Join<UserAnswer, Question> questionJoin = userAnswerRoot.join(UserAnswer_.question);
    ListJoin<Question, QuestionTranslation> questionTranslatJoin = questionJoin.join(Question_.questionTranslation);

    predicates.add(builder.equal(builder.treat(questionJoin, Question.class).get(Question_.day), day));
    predicates.add(builder.equal(builder.treat(questionJoin, Question.class).get(Question_.month), month));
    predicates.add(builder.equal(builder.treat(questionJoin, Question.class).get(Question_.year), year));
    predicates.add(builder.equal(builder.treat(questionTranslatJoin, QuestionTranslation.class).get(QuestionTranslation_.language), locale));
    predicates.add(builder.equal(userAnswerRoot.get(UserAnswer_.user), user));

    criteriaQuery.select(userAnswerRoot).where(predicates.toArray(new Predicate[]{}));

    TypedQuery<UserAnswer> query = em.createQuery(criteriaQuery);

    String queryString = query.unwrap(Query.class).getQueryString();

    return query.getSingleResult();
}

在这种情况下,问题列表包含两个QuestionTranlsation项,其中包含语言ende,但我只需要一个QuestionTranlsation条目,其中语言等于en

在这种情况下我需要做什么?

1 个答案:

答案 0 :(得分:4)

使用JPA 2.1功能JOIN ON

可以实现这一点

请参阅How to do JOIN ON query using Criteria API