【问题标题】:Using @ElementCollection in CriteriaQuery (or Querying over the content of an @ElementCollection)在 CriteriaQuery 中使用 @ElementCollection(或查询 @ElementCollection 的内容)
【发布时间】:2010-10-08 17:23:27
【问题描述】:
public enum ReportStatus { 
    SUCCCEED, FAILED;
}

public class Work {
    @ElementCollection
    @Enumerated(EnumType.STRING)
    List<ReportStatus> reportStatuses;
}

鉴于以下结构,我想执行查询以查找所有由 reportStatuses 过滤的工作。它适用于以下 hql 语法:

public List<Long> queryHQL() {
    final String query = "SELECT w.id FROM Work w JOIN w.reportStatuses s WHERE s in (:rs)";

    final List<ReportStatus> reportStatuses = new ArrayList<ReportStatus>();
    reportStatuses.add(ReportStatus.FAILED);

    return this.entityManager.createQuery(query).setParameter("rs", reportStatuses).getResultList();
}

但我想使用标准 API (jpa2),但不知道该怎么做。这是我认为最接近的尝试:

public List<Long> query() {
    final List<ReportStatus> reportStatuses = new ArrayList<ReportStatus>();
    reportStatuses.add(ReportStatus.FAILED);

    final CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

    final CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);
    final Root<Work> workModel = criteriaQuery.from(Work.class);

    final ListJoin<Work, ReportStatus> status = workModel.joinList("reportStatuses");

    final Predicate predicate = status.in(reportStatuses);

    criteriaQuery.where(predicate);
    criteriaQuery.select(workModel.<Long> get("id"));

    return this.entityManager.createQuery(criteriaQuery).getResultList();
}

我也尝试过使用休眠条件 API,但作为 jpa2 的 API,我找不到正确的语法。

【问题讨论】:

    标签: java orm jpa-2.0 criteria-api


    【解决方案1】:

    我会使用以下 CriteriaQuery 语法来做同样的事情。

    EntityManager em = entityManagerFactory.createEntityManager();
    
    final List<ReportStatus> reportStatuses = new ArrayList<ReportStatus>();
    reportStatuses.add(ReportStatus.FAILED);
    
    final CriteriaBuilder builder = em.getCriteriaBuilder();
    
    final CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);
    final Root<Work> _work = criteriaQuery.from(Work.class);
    
    /*final ListJoin<Work, ReportStatus> status = _work.joinList("reportStatuses");
    final Predicate predicate = status.in(reportStatuses);
    criteriaQuery.where(predicate);*/
    
    final Expression<List<ReportStatus>> _status = _work.get(Work_.reportStatuses);
    _status.in(reportStatuses);
    
    criteriaQuery.select(_work.get(Work_.id));
    
    List<Long> list =  em.createQuery(criteriaQuery).getResultList();
    

    更新

    谢谢,但我们不使用 生成的元模型。所以很不幸 我无法尝试你的答案。 :(

    如果您不使用 Metamodel,只需将 _work.get(Work_.reportStatuses) 替换为 _work.get("reportStatuses")。它会工作的。 :)

    【讨论】:

    • 谢谢,但我们不使用生成的元模型。所以不幸的是,我无法尝试您的答案。 :(
    • @Raphaël Brugier 检查更新部分。
    【解决方案2】:

    您可以创建此 HQL。

    String query = "SELECT w.id FROM Work w, IN(w.reportStatuses) s WHERE s = :rs";
    return this.entityManager.createQuery(query).setParameter("rs", ReportStatus.FAILED).getResultList();
    

    【讨论】:

    • 我想指出的是,当您在 @ElementCollection 中放入 @ElementCollection 时,一些 JPA SQL 支持工具会将其标记为错误,请不要相信这些工具(在那种情况下)如果您索引正确的字段,则可以流畅且非常快速地工作(这个答案实际上为我节省了几个小时的工作)。
    • 您在哪里找到此语言功能?我仔细研究了整个网络,试图解决这个确切的问题,而这个答案是我发现的唯一提到使用 IN 子句作为伪表的答案。不过,它完美无缺!
    【解决方案3】:

    我很困惑。对in(..) 的调用返回一个谓词,但似乎并没有真正执行它(它似乎没有集成到查询中——至少对我来说,它返回了根的所有成员,无论他们的集合是否与@ 相交987654322@。调试日志显示简单查询select distinct work0_.id as id18_ from Work work0_)。

    另外,如果调用者只对匹配一个值的那些感兴趣,为什么还要将reportStatuses 放在一个列表中呢?您将如何仅使用 ReportStatus.FAILED 而不是为其构建列表来进行查询?

    【讨论】:

      猜你喜欢
      • 2011-04-12
      • 2015-07-02
      • 2013-01-21
      • 2014-01-12
      • 1970-01-01
      • 2016-03-11
      • 2018-01-13
      • 1970-01-01
      • 2014-03-22
      相关资源
      最近更新 更多