2012-09-03 103 views
4

我正在嘗試測試JPA存儲庫。這是我的客戶機/測試代碼:正確使用JPA標準API,謂詞和標準查詢的方法

@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()); 
    } 

這裏是庫方法:

@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(); 
    } 

然而,測試總是失敗在assertEquals(1, boites.size());指示沒有返回結果即(java.lang.AssertionError: expected:<1> but was:<0>)。

我強烈懷疑的東西是錯誤的位置:

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

但我不知道如何「和」的標準。

任何人都可以提供建議嗎?

P.S. FYI,BoiteDataOnDemand將隨機10行插入boite表中。

編輯:代碼被編輯,使其更短。

+0

你已經發布的代碼實在是太長了。請僅張貼相關部分。 – perissf

+0

我放棄了JPA的標準API。帶有流暢API的QueryDSL更易於理解和更簡潔。參見:[queryDSL](http://www.querydsl。com/documentation) – balteo

回答

19

從您在帖子最後部分的提示開始,我同意您爲where子句添加謂詞的方式不正確。

我看到程序的方式有兩種:

第一種方式

使用謂詞

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[] {}))); 

方式二

修改環路相同的謂詞的數組

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

再次看到自己的代碼示例後,我看到你已經在正確的方式創建Predicate S的名單:你可以把它叫做criteria。你只是以錯誤的方式使用它們。看到我的第一個例子的最後一行。


EDIT 2

爲了查看是否通過使用PredicateExpressionS,未特別需要在你的情況下產生的問題,嘗試暫時刪除它們。從

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 (identifiant != null && !identifiant.trim().equals("")) { 
    Predicate condition = criteriaBuilder.like(boite.get("identifiant"), "%" + identifiant + "%"); 
    criteria.add(condition); 
} 
+0

感謝您輸入Perissf。你能告訴我'value'變量的類型和值嗎?問候。 – balteo

+0

這只是僞代碼。您可以改用Predicates。你可能不會使用循環,但是這個概念對你的'if'子句是有效的。希望很清楚。 – perissf

+0

使用最後一行代碼後,我的測試行爲是相同的,即'c.where(criteriaBuilder.and(predicates.toArray(new Predicate [predicates.size()])));'任何其他想法? – balteo