2012-09-03 3 views
4

JPA 저장소를 테스트하려고합니다. 여기JPA criteria API, Predicates의 올바른 사용법 및 CriteriaQuery의 메소드

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

하지만 방법 "과"기준 확실하지 않다 :

I 강하게 의심 뭔가 여기에 잘못된 것입니다.

누구든지 조언을 제공해 줄 수 있습니까?

P. 참고로 BoiteDataOnDemandboite 테이블에 임의의 10 개의 행을 삽입합니다.

EDIT : 코드를 더 짧게 편집했습니다.

+0

당신이 게시 한 코드에

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

에서 첫 번째 기준을 수정하는 것은 너무 깁니다. 관련 부분 만 게시하십시오. – perissf

+0

JPA의 기준 API를 포기했습니다. 유창한 API를 갖춘 QueryDSL은 이해하기가 훨씬 쉽고 간결합니다. 참조 : [queryDSL] (http : //www.querydsl.co.kr/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[] {}))); 

두 번째 술어 방법

루프에서 같은 조건을 수정의 배열을 사용하여

첫 번째 방법

:

나는 절차의 두 가지 방법을 참조

당신이 그것을 criteria를 불렀다 :
Predicate predicate = criteriaBuilder.conjunction(); 
for (Key key : keys) { 
    Predicate newPredicate = criteriaBuilder.equal(root.get(key), value); 
    predicate = criteriaBuilder.and(predicate, newPredicate); 
} 
c.where(predicate); 

다시 코드 샘플을 검토 한 결과

편집, 난 당신이 이미 올바른 방법으로 Predicate S의 목록을 만든 것을 알 수있다. 당신은 잘못된 방식으로 만 그들을 사용하고 있습니다. 나의 첫 번째 예제의 마지막 줄을 보라. 문제가 구체적 경우에 필요하지 않은 PredicateExpressionS의 사용에 의해 생성되는 경우 위해


편집 2

보고, 일시적으로 제거하려고합니다.

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

입력하신 Perissf를 보내 주셔서 감사합니다. 'value' 변수의 타입과 값을 알려주시겠습니까? 문안 인사. – balteo

+0

그건 그냥 의사 코드 였어. 귀하는 귀하의 술어를 대신 사용할 수 있습니다. 아마도 루프를 사용하지 않을 것이지만 어쨌든 개념은'if' 절에서 유효합니다. 희망은 분명하다. – perissf

+0

내 테스트의 동작은 코드의 마지막 줄, 즉'c.where (criteriaBuilder.and (predicates.toArray (new predicate [predicates.size()])));)를 사용하면 동일합니다. – balteo

관련 문제