2012-02-17 2 views
34

Не могли бы вы помочь мне в преобразовании следующих кодов в использование оператора «in» строителя критериев? Мне нужно фильтровать, используя список/массив имен пользователей, используя «in».JPA CriteriaBuilder - Как использовать оператор сравнения «IN»

Я также попытался выполнить поиск с использованием метода JPA CriteriaBuilder - «in», но не смог найти хороший результат. Так что я был бы очень признателен, если бы вы могли дать мне ссылки на эту тему. Благодарю.

Вот мои коды:

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

Внутренний Строка запроса преобразуется ниже, так что я не получаю записи, созданные двумя пользователями, так как он использует «И».

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

ответ

69

Если я хорошо понимаю, вы хотите присоединиться ScheduleRequest с User и применить статью in к userName свойству объекта User.

Мне нужно немного поработать над этой схемой. Но вы можете попробовать с этим трюком, который намного читабельнее кода, который вы опубликовали, и избегает части Join (потому что она обрабатывает логику Join вне запроса Criteria Query).

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

Для того, чтобы написать больше типобезопасный код можно также использовать метамодель, заменив строку:

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

с этим:

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

Если это работает, то вы можете попробуйте добавить логику Join в Criteria Query. Но сейчас я не могу проверить это, поэтому я предпочитаю видеть, хочет ли кто-нибудь еще попробовать.

+0

Привет, perissf, спасибо за ваш ответ. Могу ли я спросить, что такое «ScheduleRequest_»? Как мне его создать? – Jemru

+2

Это класс метамодели, автоматически созданный вашим провайдером JPA. Если вы используете Hibernate, посмотрите эту ссылку http://docs.jboss.org/hibernate/jpamodelgen/1.0/reference/en-US/html_single/ – perissf

+0

Чтение моего псевдокода. Я вижу возможное несоответствие типа. Вы присоединяетесь к userNames (String) или userIds (Integer/Long)? Pls дайте мне знать, чтобы я мог обновить свой ответ – perissf

13

Не идеальный ответ, хотя могут быть фрагменты кода.

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

Спасибо большое @gbagga, эта вещь мне очень помогла! вышеупомянутый метод (exp.in (myList)) не будет работать, если вы используете «CriteriaBuilder». Ваш метод является тем, который должен использоваться для предложения «IN» при использовании критериевBuilder. Престижность! – roneo

Смежные вопросы