programing

예제별 JPA 사양

muds 2023. 7. 30. 18:11
반응형

예제별 JPA 사양

여기 봄 부츠.제 머리를 감싸려고 노력 중입니다.JpaRepositories그리고.Specifications복잡한 쿼리를 구현하는 맥락에서 사용되며 여러 항목에 대한 "트리를 통과하는 패턴"을 확인하는 데 어려움을 겪고 있습니다.

의 표준적인 예Specification는 다음과 같습니다.

public class PersonSpecification implements Specification<Person> {
    private Person filter;

    public PersonSpecification(Person filter) {
        super();
        this.filter = filter;
    }

    public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq,
            CriteriaBuilder cb) {
        Predicate p = cb.disjunction();

        if (filter.getName() != null) {
            p.getExpressions()
                    .add(cb.equal(root.get("name"), filter.getName()));
        }

        if (filter.getSurname() != null && filter.getAge() != null) {
            p.getExpressions().add(
                    cb.and(cb.equal(root.get("surname"), filter.getSurname()),
                            cb.equal(root.get("age"), filter.getAge())));
        }

        return p;
    }
}

이 점에서.toPredicate(...)방법, 무엇이 무엇입니까?Root<Person>그리고.CriteriaQuery대표?가장 중요한 것은, 당신이 하나를 만들어야 한다는 처럼 들립니다.Specification적용할 각 필터 유형에 대해 impl. 각 사양이 하나의 술어로만 변환되기 때문에 변환되기 때문입니다.그래서 예를 들어 내가 "스밈"의 성을 가지고 25세 이상의 모든 사람들을 찾고 싶다면, 내가 글을 써야 할 것처럼 들립니다.LastnameMatchingSpecification<Person>뿐만 아니라AgeGreaterThanSpecification<Person>누가 이것을 확인하거나 설명해 줄 수 있습니까?!

처음에는 이것도 힘들었지만, 지금은 쉽게 동적 쿼리를 만들고 표당 하나의 사양을 만들고 있습니다(고급 검색이 필요할 때).

다음과 같은 개체를 생각해 보십시오.

  1. 루트가 테이블입니다.
  2. 기준 쿼리는 고유, 하위 쿼리, 순서 등을 적용하는 데 유용한 쿼리입니다.
  3. 조건은 CriteriaBuilder이며 where 절을 만드는 데 적합합니다.

--

항상 목록으로 시작한 다음 필요에 따라 AND/OR 조건 중 하나로 요약합니다.

public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
    List<Predicate> predicates = new ArrayList<>();

    if(filter.getName() != null) {
        predicates.add(cb.equal(root.get("name"), filter.getName());
    }
    if(filter.getSurname() != null) {
        predicates.add(cb.equal(root.get("surname"), filter.getSurname());
    }
    if(filter.getAge() != null) {
        predicates.add(cb.equal(root.get("age"), filter.getAge());
    }
    if(predicates.isEmpty()){
        predicates.add(cb.equal(root.get("id"), -1);
        /* 
         I like to add this because without it if no criteria is specified then 
         everything is returned. Because that's how queries work without where 
         clauses. However, if my user doesn't provide any criteria I want to 
         say no results found. 
        */
    }

    return query.where(cb.and(predicates.toArray(new Predicate[0])))
                .distinct(true).orderBy(cb.desc(root.get("name")).getRestriction();
}

이제 사용자는 이 세 가지 필드의 모든 조합을 여기에 전달할 수 있으며 이 논리는 동적으로 쿼리를 작성하여 해당 필드에 대한 조건을 포함합니다.

예: 이름 = John과 성 = Doe and age = 41 또는 이름 = John과 나이 = 41 또는 이름 = John 등.

마지막으로 문자열을 검색할 때 cb.equal이 아닌 cb.like를 사용하여 %로 부분 검색이 가능하도록 사용자 또는 프런트 엔드 시스템에서 전달하는 것을 권장합니다.

cb.like는 기본적으로 대소문자를 구분하지 않으며 다음과 같이 cb.lower 또는 cb.upper와 함께 사용해야 합니다.

 predicates.add(cb.like(cb.lower(root.get("name"), filter.getName().toLowercase());

이것이 도움이 되길 바랍니다!

도대체Root<Person>그리고.CriteriaQuery대표?

Root 쿼리의 루트이며, 기본적으로 쿼리하는 대상입니다.인어Specification이 문제에 대해 동적으로 반응하는 데 사용할 수 있습니다.이것은 예를 들어, 당신이 하나를 만들 수 있게 해줄 것입니다.OlderThanSpecification처리할Cars와 함께modelYear그리고.Drivers와 함께dateOfBirth유형을 감지하고 적절한 속성을 사용함으로써.

유사한 것이 전체 쿼리입니다. 쿼리를 검사하고 이를 기반으로 작성 중인 술어를 조정하는 데 다시 사용할 수 있습니다.

만약 내가 "스밈"의 성을 가진 25세 이상의 모든 사람들을 찾고 싶다면, 내가 글을 써야 할 것처럼 들립니다.LastnameMatchingSpecification<Person>뿐만 아니라AgeGreaterThanSpecification<Person>누가 이것을 확인하거나 설명해 줄 수 있습니까?!

저는 당신이 그것을 잘못 알고 있다고 생각합니다. Data 는 Spring Data를 합니다.Specification는 한 의 다받니습만싱만 합니다.Specification그래서 만약 당신이 모든 것을 찾길 원한다면,Person는 특정 을 만들 것입니다.Specification인용한 예제와 유사하게 두 제약 조건을 결합합니다.

은 별도로 러나별생수있다니습을 수 .Specifications를 선택한 다음 각각을 개별적으로 사용하고 결합하려면 결합된 다른 것을 만듭니다.

조인도 사용해야 하는 경우 다음과 같은 내용을 작성해야 합니다.



    @Override
    public Predicate toPredicate(Root&ltOpportunity> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
        Predicate predicate = cb.conjunction();
        ...
        predicate.getExpressions().add(cb.equal(root.join("address").get("streetName"), person.getAddress().getStreetName()));
        ...
        return predicate;
    }


public List<Transaction> getAlltransactionsBy(RecordFilter filter){
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Transaction> cq = cb.createQuery(Transaction.class);

    Root<Transaction> transaction = cq.from(Transaction.class);
    
    List<Predicate> predicatesList = new ArrayList<Predicate>();
    
    if(filter.userid > 0 ) {
        Predicate uesrIdPredicate = cb.greaterThan(transaction.get("userid"), filter.userid);
         predicatesList.add(uesrIdPredicate);
    }
    
    Predicate tranAmtBetweenPredicate = cb.between(transaction.get("tranAmt"), filter.minAmt, filter.maxAmt);
    predicatesList.add(tranAmtBetweenPredicate);
   
    
    Predicate[] tranPredicateArray = predicatesList.toArray(new Predicate[predicatesList.size()]);

    
    cq.where(tranPredicateArray);

    TypedQuery<Transaction> query = entityManager.createQuery(cq);
    return query.getResultList();
}

이 코드는 내 거래 엔티티에 대해 내 경우에 작동합니다.

언급URL : https://stackoverflow.com/questions/48647847/jpa-specifications-by-example

반응형