2010-10-08 69 views
5
public enum ReportStatus { 
    SUCCCEED, FAILED; 
} 

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

考慮下面的結構,我想執行一個查詢,以找到reportStatuses過濾所有的工作。它正常工作與以下HQL語法:在CriteriaQuery中@ElementCollection(或查詢過的@ElementCollection的內容)

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(); 
} 

我也試過用Hibernate的標準API,但作爲一個JPA2我沒能找到正確的語法。

+0

ël檢查更新的答案。 – dira 2010-12-10 12:13:24

回答

4

我會使用以下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(); 

UPDATE

謝謝,但我們不使用 生成的元模型。所以很不幸 我不能嘗試你的答案。 :(

如果你不使用的元模型,只需更換_work.get(Work_.reportStatuses)_work.get("reportStatuses")。它會工作。:)

+0

謝謝,但我們不使用生成的元模型。所以不幸的是,我不能嘗試你的答案。 :( – 2010-12-10 11:41:01

+0

@RaphaëlBrugier檢查UPDATE部分 – dira 2010-12-10 12:12:23

+0

謝謝!似乎現在工作 – 2011-02-01 11:51:24

1

我很困惑。對in(..)的調用返回一個謂詞,但似乎並沒有實際執行它(它似乎並未集成到查詢—中,至少對我而言它返回了所有根的成員,而不管它們的集合是否與reportStatuses相交。調試日誌顯示簡單查詢select distinct work0_.id as id18_ from Work work0_)。

另外,如果調用者只對那些匹配的值感興趣,爲什麼還要把reportStatuses放在列表中?你將如何使用ReportStatus.FAILED來完成查詢,而不是爲它建立一個列表?

3

您可以創建此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(); 
+0

我想指出,一些JPA SQL支持工具將標記這是一個錯誤,當你把一個'@ ElementCollection'放入'in 〜)',不要相信這些工具(在這種情況下),如果你索引正確的字段(這個答案真的省了我幾個小時的工作),這個工作流程非常快並且速度很快。 – 2014-02-28 02:46:58

+0

你在哪裏找到這種語言功能?整個網絡試圖解決這個確切的問題,這個答案是唯一提及的使用IN子句作爲我發現的僞表,儘管它工作得非常完美! – stevevls 2014-03-10 21:10:04

相關問題