2017-02-13 6 views
1

이미 생성 된 org.springframework.data.jpa.domain.Specifications가 있습니다. 이제는 내가 가입 한 테이블에서 사양을 사용하고자하는 쿼리를 작성하고 있습니다. 하지만 사양을 사용하려면 루트가 필요하지만 조인은 Join 객체를 제공합니다.JPA 스프링 데이터 지정 (조인)

Join 개체를 루트로 변환하는 방법이 있습니까? 아니면 사양과 비슷한 항목이 있습니까?

답변

3

나는 Root<T>를 만들어 RootJoin을 설정하는 관리 있도록 Tarwirdur)의 투 론강 (Turon의 솔루션은 내 필요에 맞게하지 않습니다 모든 메소드를 Join<?,T> 인스턴스에 위임하는 구현. (Join과 Root는 From의 자식 인터페이스 임) 작동하지만 아주 나에게는 더러워 보입니다.

내가 이미 Specification<JoinedEntity>을 구축했기 때문에 Tarwirdur Turon의 솔루션이 작동하지 않으며 joinedType이 내부적으로 무엇인지 모른 채로 joinedEntity가 사양과 일치하는 모든 Entity을 찾고 싶습니다.

public class JoinRoot<T> implements Root<T> { 
    private final Join<?, T> join; 
    public JoinRoot(Join<?, T> join) { 
     this.join = join; 
    } 

    // implements all Root methods, delegating them to 'this.join' (#boilerplate), 
    // cast when needed 

    @Override 
    public EntityType<T> getModel() { 
     // this one is the only one that cannot be delegated, although it's not used in my use case 
     throw new UnsupportedOperationException("getModel cannot be delegated to a JoinRoot"); 
    } 
} 

그런 다음 다음과 같이이 클래스를 사용

Specification<JoinedEntity> joinedSpecs = ... 

Specification<Entity> specs = (root, query, builder) -> { 
    // Convert Join into Root using above JoinRoot class 
    Root<JoinedEntity> r = new JoinRoot<>(root.join(Entity_.joinedEntity)); 
    return joinedSpecs.toPredicate(r, query, builder); 
} 
Specification<Entity> where = Specifications.where(specs); 

List<Entity> entities = entityRepository.findAll(where); 

내가 정말 Specification.toPredicate 방법 대신 From<Z,X>의 첫 번째 인수로 Root<X> 걸리는 이유를 궁금해,이 ...

모든 일을 쉽게 할
4

Root 개체가 필요하지 않습니다. Join 개체는 PathExpression 인터페이스의 인스턴스입니다. 작업과 예를 참조하십시오 사양에서 조인

class JoinedSpecification extends Specification<JoinedEntity>() { 
    public Predicate pathPredicate(Path<JoinedEntity> joinedEntity, CriteriaQuery<?> query, CriteriaBuilder builder) { 
     return builder.equal(joinedEnity.get(JoinedEntity_.value), 20L); 
    } 

    @Override 
    public Predicate toPredicate(Root<JoinedEntity> root, CriteriaQuery<?> query, CriteriaBuilder builder) { 
     return pathPredicate(root, query, builder); 
    } 
} 

class MySpecification extends Specification<Entity>() { 
    private static JoinedSpecification joinedSpecification = new JoinedSpecification(); 

    @Override 
    public Predicate toPredicate(Root<Entity> root, CriteriaQuery<?> query, CriteriaBuilder builder) { 
     Join<T, JoinedEntity> join = root.join(Entity_.joinedEntity, JoinType.LEFT); 

     // Some join condition 
     Path<Long> someExpr = join.get(JoinedEntity_.someExpr); 
     Long someExprCriteria = 10L; 
     join = join.on(builder.equal(someExpr, someExprCriteria)); 

     return joinedSpecification.pathPredicate(join, query, builder); 
    } 
} 

@Autowired 
JpaSpecififcationExecutor<Entity> service; 

Specification<Entity> spec = new MySpecification(); 
serivce.findAll(spec); 

그것은 제공 할 것입니다 질의

같은
SELECT e FROM Entity e LEFT JOIN e.joinedEntity j WITH j.someExpr=10 WHERE j.value = 20; 
+0

나는 이해한다, 그러나 나의 질문은, 내가 그 부품을 원한다면 무엇을해야 하는가이다. builder.equal (join.get (JoinedEntity_.value), 20L) 은 사양에 있어야 하는가? 이 경우 조건은 간단하지만 광산에서는 더 복잡하고 재사용하고 싶습니다. – freafrea

+0

@freafrea 답변을 업데이트했습니다. 조인 된 스펙 (예 : 다른 조인)에서 루트 특정 조건을 사용하지 않으면'toPredicate (Root ..)에서 호출 한'루트 '대신'Path '을 사용하여 조건을 다른 메소드로 이동할 수 있습니다. 그런 다음 코드가 중복되지 않습니다. –