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

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

die folgende Struktur gegeben, würde Ich mag eine Abfrage führen alle Arbeiten von reportStatuses gefiltert zu finden. Es funktioniert gut mit der folgenden hql Syntax:@ElementCollection Verwendung in CriteriaQuery (oder Abfragen über den Inhalt eines @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(); 
} 

Aber ich mag die Kriterien API (jpa2) verwenden, und kann nicht herausfinden, wie es zu tun. Hier ist mein nächster Versuch denke ich:

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

ich auch mit dem Hibernate-Kriterien API versucht habe, aber als jpa2, die ich versäumt habe die richtige Syntax zu finden.

+0

Überprüfen Sie die aktualisierte Antwort. – dira

Antwort

4

würde ich für das gleiche tun folgende CriteriaQuery Syntax.

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

Danke, aber wir verwenden, um die erzeugt Metamodell nicht. Also leider kann ich nicht mit deiner Antwort versuchen. :(

Wenn Sie Metamodell nicht verwenden, ersetzen Sie einfach _work.get(Work_.reportStatuses) mit _work.get("reportStatuses"). Es wird funktionieren. :)

+0

Danke, aber wir benutzen das generierte Metamodell nicht. Also kann ich leider nicht mit deiner Antwort versuchen. :( –

+0

@ Raphaël Brugier Überprüfen Sie das Update Teil. – dira

+0

Dank! Scheint jetzt arbeiten. –

1

Ich bin verwirrt. Der Aufruf von in(..) gibt ein Prädikat aber scheint nicht wirklich, es zu erzwingen (es nicht in die Abfrage integriert zu sein scheint — zumindest für mich alle Mitglieder der Wurzel zurückgeführt, ob ihre Sammlungen durchschnitten mit reportStatuses. Die Debug-Protokoll zeigt die einfache Abfrage select distinct work0_.id as id18_ from Work work0_).

Auch, warum reportStatuses in einer Liste plagen setzen, wenn die Anrufer in denen nur daran interessiert ist, einen Wert passend? Wie würden Sie die Abfrage w/nur mit ReportStatus.FAILED anstatt eine Liste dafür erstellen?

3

Sie können diese HQL erstellen.

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

Ich mag würde darauf hinweisen, dass einige JPA SQL unterstützende Werkzeuge dies als Fehler markiert wird, wenn Sie setzen ein '@ ElementCollection' im' in (~) ', NICHT diesen Tools vertrauen (in diesem Fall) dies funktioniert fließend und ziemlich schnell, wenn Sie die richtigen Felder indizieren (Diese Antwort hat mir tatsächlich ein paar Stunden Arbeit erspart.) –

+0

Wo haben Sie diese Sprachfunktion gefunden? Überall im Internet versucht man, genau dieses Problem zu lösen, und diese Antwort ist die einzige Erwähnung der Verwendung der IN-Klausel als Pseudo-Tabelle, die ich gefunden habe. – stevevls