web-dev-qa-db-fra.com

JPA CriteriaBuilder - Comment utiliser l'opérateur de comparaison "IN"

Pouvez-vous m'aider, s'il vous plaît, à convertir les codes suivants en utilisant l'opérateur "in" de générateur de critères? J'ai besoin de filtrer en utilisant list/array of usern names en utilisant "in".

J'ai également essayé d'effectuer une recherche à l'aide de JPA CriteriaBuilder - méthode "in" mais je ne peux pas trouver un bon résultat. J'apprécierais donc beaucoup si vous pouvez me donner des URL de référence pour ce sujet. Merci.

Voici mes codes:

//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 chaîne de requête interne est convertie ci-dessous, je ne reçois donc pas les enregistrements créés par les deux utilisateurs, car elle utilise "AND".

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

Si je comprends bien, vous souhaitez rejoindre ScheduleRequest avec User et appliquer la clause in à la propriété userName de l'entité User .

J'aurais besoin de travailler un peu sur ce schéma. Mais vous pouvez essayer avec cette astuce, qui est beaucoup plus lisible que le code que vous avez posté, et évite la partie Join (car elle gère la logique Join en dehors de la requête de critères).

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

Afin d'écrire plus de code de type-sûr, vous pouvez également utiliser Metamodel en remplaçant cette ligne:

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

avec ça:

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

Si cela fonctionne, essayez d’ajouter la logique Join au Criteria Query. Mais pour le moment, je ne peux pas le tester, alors je préfère voir si quelqu'un d'autre veut essayer.

86
perissf

Ce n’est peut-être pas une réponse parfaite, mais des extraits de code pourraient aider.

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

    }
14
baba.kabira