JPA CriteriaBuilder - 如何使用“IN”比较运算符

65

请问如何将以下代码转换为使用Criteria Builder的“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();

内部的查询字符串被转换为以下内容,因此我无法获取由这两个用户创建的记录,因为它使用了“AND”。

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

112
如果我理解得没错的话,您想要将ScheduleRequestUser进行连接,并对实体UseruserName属性应用in子句。

我需要对这个模式进行一些处理。不过,您可以尝试这个技巧,它比您发布的代码更易读,并且避免了Join部分(因为它在Criteria查询之外处理了Join逻辑)。
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);
为了编写更加类型安全的代码,您还可以使用元模型(Metamodel)来替换这一行:
Expression<String> exp = scheduleRequest.get("createdBy");

用这个代码:

Expression<String> exp = scheduleRequest.get(ScheduleRequest_.createdBy);
如果它可行,那么您可以尝试将Join逻辑添加到Criteria Query中。但现在我无法测试它,所以我更喜欢看看是否有其他人想尝试。

2
这是由您的JPA提供程序自动生成的元模型类。如果您正在使用Hibernate,请查看此链接http://docs.jboss.org/hibernate/jpamodelgen/1.0/reference/en-US/html_single/。 - perissf
阅读我的伪代码,我发现可能存在类型不匹配的问题。您是使用userNames(字符串)还是userIds(整数/长整数)进行连接?请告诉我,以便我可以更新我的答案。 - perissf
嗨,perissf,我正在使用字符串userNames。我只是遵循我们的架构,其中没有“_”下划线bean,所以我不确定该如何做。但我仍然会尝试遵循你的链接。谢谢。 - Jemru
很好了解!关于自动生成的类,即所谓的元模型,你有没有阅读我给你的链接?如果你在这方面遇到问题,请提出一个新的问题,并提供详细信息。 - perissf
我一直在使用这个,但是不断出现“无法转换为字符串”错误。 - user1735921
显示剩余4条评论

21

虽然不完美,但也许代码片段可以帮助。

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

    }

2
非常感谢@gbagga,这个东西帮了我很多!当您使用“CriteriaBuilder”时,上述方法(exp.in(myList))将无法工作。在使用CriteriaBuilder时,应使用您的方法来进行“IN”子句。赞! - roneo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接