【问题标题】:JPA Criteria Join OneToMany table where clause does not workJPA Criteria Join OneToMany table where 子句不起作用
【发布时间】:2017-05-13 18:01:00
【问题描述】:

我有两张桌子。

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 标准的 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;

但是这个返回给我的 Question 类与 List QuestionTranslation 有两个条目,其中语言字段等于 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 标准的 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,但我只需要一个语言等于 en 的 QuestionTranlsation 条目。

在这种情况下我该怎么办?

【问题讨论】:

    标签: java spring hibernate jpa-2.0


    【解决方案1】:

    这可以通过 JPA 2.1 功能 JOIN ON 实现

    How to do JOIN ON query using Criteria API

    【讨论】:

    • 我为什么需要它?您可以访问来自翻译的问题。
    • 我使用 JPA 2.1,给我一个建议如何使用 'JOIN ON language' ?
    • 你能解决这个问题吗@dikkini
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-15
    • 1970-01-01
    • 2017-01-18
    • 2018-05-13
    • 1970-01-01
    • 2017-08-24
    • 2017-01-16
    相关资源
    最近更新 更多