2012-02-17 12 views
34

Czy możesz mi pomóc, jak przekonwertować następujące kody do używania operatora "in" konstruktora kryteriów? Potrzebuję filtrować przy użyciu listy/tablicy nazw użytkownika za pomocą "in".JPA CriteriaBuilder - Jak używać operatora porównania "IN"

Próbowałem również wyszukiwania przy użyciu JPA CriteriaBuilder - metoda "in", ale nie można znaleźć dobrego wyniku. Więc naprawdę doceniam również, jeśli możesz podać mi adresy URL dla tego tematu. Dzięki.

Oto moje kody:

//usersList is a list of User that I need to put inside IN operator 

CriteriaBuilder builder = getJpaTemplate().getEntityManagerFactory().getCriteriaBuilder(); 
CriteriaQuery<ScheduleRequest> criteria = builder.createQuery(ScheduleRequest.class); 

Root<ScheduleRequest> scheduleRequest = criteria.from(ScheduleRequest.class); 
criteria = criteria.select(scheduleRequest); 

List<Predicate> params = new ArrayList<Predicate>(); 

List<ParameterExpression<String>> usersIdsParamList = new ArrayList<ParameterExpression<String>>(); 

for (int i = 0; i < usersList.size(); i++) { 
ParameterExpression<String> usersIdsParam = builder.parameter(String.class); 
params.add(builder.equal(scheduleRequest.get("createdBy"), usersIdsParam)); 
usersIdsParamList.add(usersIdsParam); 
} 

criteria = criteria.where(params.toArray(new Predicate[0])); 

TypedQuery<ScheduleRequest> query = getJpaTemplate().getEntityManagerFactory().createEntityManager().createQuery(criteria); 

for (int i = 0; i < usersList.size(); i++) { 
query.setParameter(usersIdsParamList.get(i), usersList.get(i).getUsername()); 
} 

List<ScheduleRequest> scheduleRequestList = query.getResultList(); 

wewnętrznego łańcucha zapytania jest konwertowany do dołu, więc nie dostać rekordy utworzone przez dwóch użytkowników, ponieważ jest przy użyciu „AND”.

select generatedAlias0 from ScheduleRequest as generatedAlias0 where (generatedAlias0.createdBy=:param0) and (generatedAlias0.createdBy=:param1) order by generatedAlias0.trackingId asc 

Odpowiedz

69

Jeśli dobrze rozumiem, że chcesz dołączyć do ScheduleRequest z User i zastosować klauzulę in do właściwości podmiotu UseruserName.

Będę musiał trochę popracować nad tym schematem. Ale możesz wypróbować tę sztuczkę, która jest znacznie bardziej czytelna niż kod, który wysłałeś, i unika części Join (ponieważ obsługuje ona logikę Join poza zapytaniem Kryteriów).

List<String> myList = new ArrayList<String>(); 
for (User u : usersList) { 
    myList.add(u.getUsername()); 
} 
Expression<String> exp = scheduleRequest.get("createdBy"); 
Predicate predicate = exp.in(myList); 
criteria.where(predicate); 

Aby napisać więcej type-safe kod można też użyć metamodel zastępując ten wiersz:

Expression<String> exp = scheduleRequest.get("createdBy"); 

z tym:

Expression<String> exp = scheduleRequest.get(ScheduleRequest_.createdBy); 

Jeśli działa, to może spróbuj dodać logikę Join do Criteria Query. Ale teraz nie mogę tego przetestować, więc wolę sprawdzić, czy ktoś inny chce spróbować.

+0

Witam perissf, dziękuję za odpowiedź. Czy mogę zapytać, co to jest "ScheduleRequest_"? Jak mogę to zrobić? – Jemru

+2

Jest to klasa Metamodel wygenerowana automatycznie przez dostawcę JPA. Jeśli używasz Hibernate, sprawdź ten link http://docs.jboss.org/hibernate/jpamodelgen/1.0/reference/en-US/html_single/ – perissf

+0

Czytanie mojego pseudokodu Widzę możliwą rozbieżność typu. Czy łączysz się z userNames (String) lub userIds (Integer/Long)? Pls daj mi znać, abym mógł zaktualizować moją odpowiedź: – perissf

13

Nie jest to idealna odpowiedź, choć mogą to być urywki kodu.

public <T> List<T> findListWhereInCondition(Class<T> clazz, 
      String conditionColumnName, Serializable... conditionColumnValues) { 
     QueryBuilder<T> queryBuilder = new QueryBuilder<T>(clazz); 
     addWhereInClause(queryBuilder, conditionColumnName, 
       conditionColumnValues); 
     queryBuilder.select(); 
     return queryBuilder.getResultList(); 

    } 


private <T> void addWhereInClause(QueryBuilder<T> queryBuilder, 
      String conditionColumnName, Serializable... conditionColumnValues) { 

     Path<Object> path = queryBuilder.root.get(conditionColumnName); 
     In<Object> in = queryBuilder.criteriaBuilder.in(path); 
     for (Serializable conditionColumnValue : conditionColumnValues) { 
      in.value(conditionColumnValue); 
     } 
     queryBuilder.criteriaQuery.where(in); 

    } 
+1

Wielkie dzięki @gbagga, ta rzecz bardzo mi pomogła! powyższa metoda (exp.in (myList)) nie zadziała, gdy używasz "CriteriaBuilder". Twoja metoda jest tą, która powinna być użyta w klauzuli "IN" podczas korzystania z kryterium kryteriów. Sława! – roneo