2012-02-17 20 views
34

¿Me puede ayudar por favor a convertir los siguientes códigos para usar el operador "in" del generador de criterios? Necesito filtrar usando list/array de nombres de usuario usando "in".JPA CriteriaBuilder - Cómo utilizar el operador de comparación "IN"

También traté de buscar utilizando JPA CriteriaBuilder - método "in" pero no puedo encontrar un buen resultado. Así que realmente apreciaría también si me puede dar URL de referencia para este tema. Gracias.

Aquí es mis códigos:

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

La cadena de consulta interna se convierte a continuación, por lo que no reciben los registros creados por los dos usuarios, porque está utilizando "Y".

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

Respuesta

69

Si he entendido bien, que desea unirse ScheduleRequest con User y aplicar la cláusula inuserName a la propiedad de la entidad User.

Tendría que trabajar un poco en este esquema. Pero puedes probar con este truco, que es mucho más legible que el código que publicaste, y evita la parte Join (porque maneja la lógica Join fuera de la consulta de Criteria).

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

Para escribir más código de seguridad de tipos también se podría utilizar metamodelo mediante la sustitución de esta línea:

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

con esto:

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

Si funciona, entonces es posible intente agregar la lógica Join en el Criteria Query. Pero ahora mismo no puedo probarlo, así que prefiero ver si alguien más quiere probarlo.

+0

Hola perissf, gracias por tu respuesta. ¿Puedo preguntar, por favor, qué es "ScheduleRequest_"? ¿Cómo lo creo? – Jemru

+2

Es una clase Metamodel autogenerada por su proveedor JPA. Si está utilizando Hibernate, consulte este enlace http://docs.jboss.org/hibernate/jpamodelgen/1.0/reference/en-US/html_single/ – perissf

+0

Leyendo mi pseudocódigo Veo una posible discrepancia de tipo. ¿Se está uniendo con userNames (String) o userIds (Integer/Long)? Por favor, hágamelo saber para que pueda actualizar mi respuesta – perissf

13

Aunque la respuesta no es perfecta, los fragmentos de código pueden ser útiles.

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

Muchas gracias @gbagga, ¡esto me ayudó mucho! el método anterior (exp.in (myList)) no funcionará cuando esté utilizando "CriteriaBuilder". Su método es el que debe usarse para la cláusula "IN" cuando se utiliza criteriaBuilder. ¡Prestigio! – roneo

Cuestiones relacionadas