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

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

Data la seguente struttura, vorrei eseguire una query per trovare tutti i lavori filtrata da reportStatuses. Funziona bene con la seguente sintassi HQL:Utilizzando @ElementCollection in CriteriaQuery (o Interrogazione sul contenuto di un @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(); 
} 

Ma vorrei utilizzare l'API criteri (jpa2), e non riesco a capire come farlo. Qui è la mia prova più vicino penso:

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

Ho anche provato con il criterio Hibernate API, ma come il jpa2 quello che ho non è riuscito a trovare la giusta sintassi.

+0

ël controllare la risposta aggiornata. – dira

risposta

4

Vorrei utilizzare la seguente sintassi CriteriaQuery per fare la stessa cosa.

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

Grazie, ma noi non utilizzare il metamodello generato. Quindi sfortunatamente Non posso provare con la tua risposta. :(

Se non si utilizza Metamodel, basta sostituire _work.get(Work_.reportStatuses) con _work.get("reportStatuses"). Funzionerà. :)

+0

Grazie, ma non usiamo il metamodello generato. Quindi sfortunatamente non posso provare con la tua risposta. :( –

+0

@ Raphaël Brugier Controlla la parte UPDATE – dira

+0

Grazie! Sembra che funzioni ora –

1

Sono confuso. La chiamata a in(..) restituisce un predicato ma non sembra applicarlo effettivamente (non sembra essere integrato nella query — almeno per me ha restituito tutti i membri della radice indipendentemente dal fatto che le loro raccolte abbiano intersecato con reportStatuses. registro di debug mostra la semplice query select distinct work0_.id as id18_ from Work work0_).

Inoltre, perché preoccuparsi di inserire reportStatuses in un elenco se il chiamante è interessato solo a quelli corrispondenti a un valore? Come faresti la query usando solo ReportStatus.FAILED invece di costruire un elenco per questo?

3

È possibile creare questo 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

Vorrei sottolineare che alcuni strumenti di supporto JPA SQL lo contrassegneranno come un errore quando inserisci un '@ ElementCollection' in' in (~) ', NON fidatevi di quegli strumenti (in questo caso) funziona senza problemi e abbastanza velocemente se indicizzate i campi giusti (Questa risposta mi ha permesso di risparmiare alcune ore di lavoro) –

+0

Dove hai trovato questa funzione linguistica? in tutto il web cercando di risolvere questo problema esatto, e questa risposta è l'unica menzione dell'uso della clausola IN come uno pseudo-tavolo che ho trovato: funzionava perfettamente, però! – stevevls