正确使用JPA标准API,Predicates和CriteriaQuery的方法 [英] Correct usage of JPA criteria API, Predicates and where method of CriteriaQuery

查看:4313
本文介绍了正确使用JPA标准API,Predicates和CriteriaQuery的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在测试一个JPA存储库。这里是我的客户端/测试代码:

  @Test 
public void testFindBoitesByMultiFieldWithIdentifiantSet(){
BoiteDataOnDemand dod = new BoiteDataOnDemand();
Boite boite = dod.getSpecificBoite(0);
boite.setIdentifiant(theIdentifiant);
boiteRepository.save(boite);
assertEquals(10,Boite.countBoites());
BoiteQueryInfo boiteQueryInfo = new BoiteQueryInfo();
boiteQueryInfo.setIdentifiant(theIdentifiant);
列表< Boite> boites = boiteRepository.findBoitesByMultiField(boiteQueryInfo,1,5,identifiant,desc);
assertEquals(1,boites.size());
}

以下是储存库方法:

  @Override 
public List< Boite> findBoitesByMultiField(BoiteQueryInfo boiteQueryInfo,Integer firstResult_,Integer maxResults_,String sort_,String order_){
log.debug(findBoitesByMultiField);

final String identifiant = boiteQueryInfo.getIdentifiant();
final日期dateOuvertureFrom = boiteQueryInfo.getDateOuvertureFrom();

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery< Boite> c = criteriaBuilder.createQuery(Boite.class);
Root< Boite> boite = c.from(Boite.class);
列表<谓词> criteria = new ArrayList< Predicate>();
...
if(identifiant!= null&&!identifiant.trim()。equals()){
ParameterExpression< String> parameter = criteriaBuilder.parameter(String.class,identifiant);
谓词条件= criteriaBuilder.like(boite。< String> get(identifiant),parameter);
criteria.add(condition);
}

if(dateOuvertureFrom!= null&& dateOuvertureTo!= null){
ParameterExpression< Date> parameterDateOuvertureFrom = criteriaBuilder.parameter(Date.class,dateOuvertureFrom);
ParameterExpression< Date> parameterDateOuvertureTo = criteriaBuilder.parameter(Date.class,dateOuvertureTo);
谓词条件= criteriaBuilder.between(boite。< Date> get(dateOuverture),parameterDateOuvertureFrom,parameterDateOuvertureTo);
criteria.add(condition);
} else if(dateOuvertureFrom!= null){
ParameterExpression< Date>参数= criteriaBuilder.parameter(Date.class,dateOuvertureFrom);
谓词条件= criteriaBuilder.greaterThanOrEqualTo(boite。< Date> get(dateOuverture),parameter);
criteria.add(condition);
} else if(dateOuvertureTo!= null){
ParameterExpression< Date>参数= criteriaBuilder.parameter(Date.class,dateOuvertureTo);
谓词条件= criteriaBuilder.lessThanOrEqualTo(boite。< Date> get(dateOuverture),parameter);
criteria.add(condition);

$ b ...
if(order.equalsIgnoreCase(desc)){
c.orderBy(criteriaBuilder.desc(boite.get(sort) ));
} else {
c.orderBy(criteriaBuilder.asc(boite.get(sort)));
}

for(Predicate predicate:criteria){
c.where(criteriaBuilder.and(predicate));
}

TypedQuery< Boite> q = em.createQuery(c);如果(识别!=空&&!identifiant.trim()。等于()){
q.setParameter(识别,%+识别+ %); (dateOuvertureFrom!= null&& dateOuvertureTo!= null){
q.setParameter(dateOuvertureFrom,dateOuvertureFrom);
}

if
q.setParameter(dateOuvertureTo,dateOuvertureTo);
} else if(dateOuvertureFrom!= null){
q.setParameter(dateOuvertureFrom,dateOuvertureFrom);
} else if(dateOuvertureTo!= null){
q.setParameter(dateOuvertureTo,dateOuvertureTo);
}

...
return q.setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
}

但是,测试总是在 assertEquals(1,boites.size()); 指示没有返回结果,即( java.lang.AssertionError:expected:< 1> :

我强烈怀疑这里有些问题:



$ b

for(Predicate predicate:criteria){
c.where(criteriaBuilder.and(predicate));
}

但我不确定如何和标准。



任何人都可以提供建议吗?



PS仅供参考, BoiteDataOnDemand 将随机10行插入 boite 表中。



编辑:编辑代码使其缩短。

解决方案

从您的帖子最后部分的提示开始,我同意你为添加谓词的方式,其中子句不正确。



我看到两种方法继续:

第一种方式 使用谓词数组

  List< Predicate> predicates = new ArrayList< Predicate>(); (key key:keys){
predicates.add(criteriaBuilder.equal(root.get(key),value));
}
c.where(criteriaBuilder.and(predicates.toArray(new Predicate [] {})));

第二种方式

在循环中修改相同的谓词

 谓词predicate = criteriaBuilder.conjunction(); (Key key:keys)
{
Predicate newPredicate = criteriaBuilder.equal(root.get(key),value);
predicate = criteriaBuilder.and(predicate,newPredicate);
}
c.where(谓词);






EDITED



再次查看代码示例后,我看到您已经以正确的方式创建了 Predicate S列表:您已将它称为标准。你只是以错误的方式使用它们。看到我的第一个例子的最后一行。




编辑2



为了通过使用 PredicateExpressionS 来查看问题是否是由您的情况特别需要的,请尝试暂时删除它们。修改你的第一个标准从

  if(identifiant!= null&&!identifiant.trim()。equals( )){
ParameterExpression< String> parameter = criteriaBuilder.parameter(String.class,identifiant);
谓词条件= criteriaBuilder.like(boite。< String> get(identifiant),parameter);
criteria.add(condition);



<$ p如果(identify)!= null&&!identifiant.trim()。equals()){
Predicate condition = criteriaBuilder.like(boite.get(identifiant ),%+ identifiant +%);
criteria.add(condition);
}


I am trying to test a JPA repository. Here is my client/test code:

@Test
    public void testFindBoitesByMultiFieldWithIdentifiantSet() {
        BoiteDataOnDemand dod = new BoiteDataOnDemand();
        Boite boite = dod.getSpecificBoite(0);
        boite.setIdentifiant("theIdentifiant");
        boiteRepository.save(boite);
        assertEquals(10, Boite.countBoites());
        BoiteQueryInfo boiteQueryInfo = new BoiteQueryInfo();
        boiteQueryInfo.setIdentifiant("theIdentifiant");
        List<Boite> boites = boiteRepository.findBoitesByMultiField(boiteQueryInfo, 1, 5, "identifiant", "desc");
        assertEquals(1, boites.size());
    }

Here is the repository method:

@Override
    public List<Boite> findBoitesByMultiField(BoiteQueryInfo boiteQueryInfo, Integer firstResult_, Integer maxResults_, String sort_, String order_) {
        log.debug("findBoitesByMultiField");

        final String identifiant = boiteQueryInfo.getIdentifiant();
        final Date dateOuvertureFrom = boiteQueryInfo.getDateOuvertureFrom();

        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
        CriteriaQuery<Boite> c = criteriaBuilder.createQuery(Boite.class);
        Root<Boite> boite = c.from(Boite.class);
        List<Predicate> criteria = new ArrayList<Predicate>();
            ...
        if (identifiant != null && !identifiant.trim().equals("")) {
            ParameterExpression<String> parameter = criteriaBuilder.parameter(String.class, "identifiant");
            Predicate condition = criteriaBuilder.like(boite.<String> get("identifiant"), parameter);
            criteria.add(condition);
        }

        if (dateOuvertureFrom != null && dateOuvertureTo != null) {
            ParameterExpression<Date> parameterDateOuvertureFrom = criteriaBuilder.parameter(Date.class, "dateOuvertureFrom");
            ParameterExpression<Date> parameterDateOuvertureTo = criteriaBuilder.parameter(Date.class, "dateOuvertureTo");
            Predicate condition = criteriaBuilder.between(boite.<Date> get("dateOuverture"), parameterDateOuvertureFrom, parameterDateOuvertureTo);
            criteria.add(condition);
        } else if (dateOuvertureFrom != null) {
            ParameterExpression<Date> parameter = criteriaBuilder.parameter(Date.class, "dateOuvertureFrom");
            Predicate condition = criteriaBuilder.greaterThanOrEqualTo(boite.<Date> get("dateOuverture"), parameter);
            criteria.add(condition);
        } else if (dateOuvertureTo != null) {
            ParameterExpression<Date> parameter = criteriaBuilder.parameter(Date.class, "dateOuvertureTo");
            Predicate condition = criteriaBuilder.lessThanOrEqualTo(boite.<Date> get("dateOuverture"), parameter);
            criteria.add(condition);
        }

            ...    
        if (order.equalsIgnoreCase("desc")) {
            c.orderBy(criteriaBuilder.desc(boite.get(sort)));
        } else {
            c.orderBy(criteriaBuilder.asc(boite.get(sort)));
        }

        for (Predicate predicate : criteria) {
            c.where(criteriaBuilder.and(predicate));
        }

        TypedQuery<Boite> q = em.createQuery(c);

        if (identifiant != null && !identifiant.trim().equals("")) {
            q.setParameter("identifiant", "%" + identifiant + "%");
        }

        if (dateOuvertureFrom != null && dateOuvertureTo != null) {
            q.setParameter("dateOuvertureFrom", dateOuvertureFrom);
            q.setParameter("dateOuvertureTo", dateOuvertureTo);
        } else if (dateOuvertureFrom != null) {
            q.setParameter("dateOuvertureFrom", dateOuvertureFrom);
        } else if (dateOuvertureTo != null) {
            q.setParameter("dateOuvertureTo", dateOuvertureTo);
        }

            ...    
        return q.setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }

However, the test always fails at assertEquals(1, boites.size()); indicating that no result is returned i.e. (java.lang.AssertionError: expected:<1> but was:<0>).

I strongly suspect something is wrong here:

for (Predicate predicate : criteria) {
            c.where(criteriaBuilder.and(predicate));
        }

But I am not sure how to "and" the criteria.

Can anyone please provide advice?

P.S. FYI, BoiteDataOnDemand inserts random 10 rows into the boite table.

EDIT: code was edited to make it shorter.

解决方案

Starting from your hint in the final part of your post, I agree that the way you are adding predicates for the where clause is not correct.

I see two ways of proceeding:

First way

Using an array of predicates

List<Predicate> predicates = new ArrayList<Predicate>();
for (Key key : keys) {
    predicates.add(criteriaBuilder.equal(root.get(key), value));
}
c.where(criteriaBuilder.and(predicates.toArray(new Predicate[] {})));

Second way

Modifying the same predicate in the loop

Predicate predicate = criteriaBuilder.conjunction();
for (Key key : keys) {
    Predicate newPredicate = criteriaBuilder.equal(root.get(key), value);
    predicate = criteriaBuilder.and(predicate, newPredicate);
}
c.where(predicate);


EDITED

After looking again your code sample, I see that you have already created in the correct way a list of PredicateS: you have called it criteria. You are only using them in the wrong way. See the last line of my first example.


EDIT 2

In order to see if the problem is generated by the use of PredicateExpressionS, that are not specifically needed in your case, try to temporarily remove them. Modify your first criteria from

if (identifiant != null && !identifiant.trim().equals("")) {
    ParameterExpression<String> parameter = criteriaBuilder.parameter(String.class, "identifiant");
    Predicate condition = criteriaBuilder.like(boite.<String> get("identifiant"), parameter);
    criteria.add(condition);
}

to

if (identifiant != null && !identifiant.trim().equals("")) {
    Predicate condition = criteriaBuilder.like(boite.get("identifiant"), "%" + identifiant + "%");
    criteria.add(condition);
}

这篇关于正确使用JPA标准API,Predicates和CriteriaQuery的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆