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

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

Biorąc pod uwagę następującą strukturę, chciałbym przeprowadzić kwerendę, aby znaleźć wszystkie prace przefiltrowaną przez reportStatuses. Współpracuje z następującą składnią HQL:Korzystanie @ElementCollection w CriteriaQuery (lub Zapytania nad treścią w @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(); 
} 

Ale chciałbym użyć API kryteria (jpa2), i nie może dowiedzieć się, jak to zrobić. Oto moja najbliższa próba myślę:

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

Próbowałem zostały również kryteria hibernacji API, ale jako jpa2 jednej Zawiodłem znaleźć poprawną składnię.

+0

ël sprawdź zaktualizowaną odpowiedź. – dira

Odpowiedz

4

Chciałbym użyć następującej składni CriteriaQuery do robienia tego samego.

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

Dzięki, ale nie używać wygenerowany metamodel. Tak więc niestety Nie mogę spróbować z twoją odpowiedzią. :(

Jeśli nie używać metamodel, wystarczy zastąpić _work.get(Work_.reportStatuses) z _work.get("reportStatuses"). To będzie działać. :)

+0

Dzięki, ale nie używamy wygenerowanego metamodelu. Tak więc niestety nie mogę spróbować z twoją odpowiedzią. :( –

+0

@ Raphaël Brugier Sprawdź część UPDATE – dira

+0

Dziękujemy! Wygląda na to, że teraz działa –

1

jestem zdezorientowany. Wywołanie do in(..) zwraca predykat, ale nie wydaje się, aby to faktycznie wymusić (nie wydaje się być zintegrowany z zapytaniem — przynajmniej dla mnie zwrócił wszystkich członków root bez względu na to, czy ich zbiory przecinały się z reportStatuses. dziennik debugowania pokazuje proste zapytanie select distinct work0_.id as id18_ from Work work0_).

Po co zawracać sobie głowę umieszczaniem na liście raportów, jeśli osoba dzwoniąca jest zainteresowana tylko tymi, które pasują do jednej wartości? Jak zrobiłbyś zapytanie z/po prostu używając ReportStatus.FAILED zamiast budować listę dla tego?

3

Możesz utworzyć ten 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

Chciałbym wskazać, że niektóre narzędzia wspierające JPA SQL oznaczą to jako błąd, gdy wstawisz '@ ElementCollection' w' in (~) ', NIE ufaj tym narzędziom (w tym przypadku) działa to płynnie i dość szybko, jeśli indeksujesz właściwe pola (Ta odpowiedź pozwoliła mi zaoszczędzić kilka godzin pracy) –

+0

Gdzie znalazłeś tę funkcję językową? w całej sieci, próbując rozwiązać ten dokładny problem, a ta odpowiedź jest jedyną wzmianką o używaniu klauzuli IN jako pseudo-tabeli, którą znalazłem, ale działało bezbłędnie! – stevevls

Powiązane problemy