2014-09-02 2 views
5

ID 목록을 기반으로 하위 엔티티 컬렉션을 필터링해야하는 엔티티 서비스가 있습니다. 내 서비스에는 부모 엔티티의 ID와 일부 자식 엔티티의 ID를받는 공용 메소드가 있습니다.하위 엔티티 컬렉션을 술어로 필터링하는 방법은 무엇입니까?

기본적으로 JPA는 모든 관련 엔티티를 가져오고 실제 동작을 알 수 있습니다. 그러나 우리는 서비스의 성능에 대해 연구해야합니다. 따라서 모든 관련 엔티티를 가져 오지 않고 많은 루프 (ID의 필터 및 date 속성 같은 다른 속성의 필터)로 필터링하는 대신 요청한 엔티티 만 가져오고 싶습니다.

내 부모 엔티티

@Entity 
@Table(name = "MyParent") 
public class MyParentEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, 
     generator = "SEQ_MyParent") 
    @SequenceGenerator(allocationSize = 1, name = "SEQ_MyParent", 
     sequenceName = "SEQ_MyParent") 
    @Column(name = "ID_PARENT") 
    private Long id; 

    @OneToMany(mappedBy = "myParent", cascade = CascadeType.ALL, 
     fetch = FetchType.EAGER, orphanRemoval = true) 
    private final List<MyChildEntity> myChild = new ArrayList<MyChildEntity>(); 

} 

내 아이 엔티티

@Entity 
@Table(name = "MyChild") 
public class MyChildEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, 
     generator = "SEQ_MyChild") 
    @SequenceGenerator(allocationSize = 1, name = "SEQ_MyChild", 
     sequenceName = "SEQ_MyChild") 
    @Column(name = "ID_CHILD") 
    private Long id; 

    @ManyToOne 
    @JoinColumn(name = "ID_PARENT") 
    private MyParentEntity myParent; 
} 

내 DB에서 데이터를 얻기 위해 스프링 데이터 CrudRepository를 사용하고 있는데 나는 또한 JpaSpecificationExecutor이 술어를 사용하여 확장합니다.

public interface MyParentRepository extends CrudRepository<MyParentEntity, Long>, 
    JpaSpecificationExecutor<MyParentEntity> { 
} 

여기서는 CrudRepository findOne() 메서드를 사용하지만 일반 Long 매개 변수 대신 Specification 개체를 사용합니다.

또한, 나는 다음과 같은 호출 배수 사양의 객체를 결합 :

this.myParentRepository.findOne(Specifications 
    .where(firstSpecification(parentId)) 
    .and(secondSpecification(childrenIdsList))); 

나는 두 아이 엔티티에 연결 한 부모와 간단한 JUnit 테스트를 만들었습니다. 내 요청에 따라 제공된 ID로 상위 엔티티를 가져올 수 있습니다. 그러나 자식 id를 제공하더라도 항상 부모 내부의 자식 엔터티를 모두 가져옵니다.

toPredicate 메서드가 재정의 된 새로운 Specification 개체를 반환하는 내 메서드에서 내 자식 컬렉션을 필터링하고 내가 관심있어하는 개체 만 가져올 수있는 조건부를 만들 수 없습니다. 나는 Hibernate Criteria가 "Restrictions"를 추가 할 수 있다는 것을 알고 있지만 toPredicate 메소드와 함께 제공되는 CriteriaBuilder에서는이를 사용할 수 없다.

public static Specification<MyParentEntite> firstSpecification(final Long id) { 
    return new Specification<MyParentEntite>() { 

     @Override 
     public Predicate toPredicate(Root<MyParentEntite> root, 
      CriteriaQuery<?> query, CriteriaBuilder cb) { 

      Predicate predicate = cb.equal(root.get(MyParentEntity_.id), id); 
      return cb.and(predicate); 
     } 
    }; 
} 

public static Specification<MyParentEntite> secondSpecification(final List<Long> ids) { 
    return new Specification<MyParentEntite>() { 

     @Override 
     public Predicate toPredicate(Root<MyParentEntite> root, 
      CriteriaQuery<?> query, CriteriaBuilder cb) { 

      Root<MyChildEntity> child = query.from(MyChildEntity.class); 
      Expression<Long> exp = child.get(MyChildEntity_.id); 
      Predicate p = exp.in(ids); 
      return cb.and(p); 
     } 
    }; 
} 

secondSpecification() 메서드에서는 Entity에서 직접 Root 대신 ListJoin을 사용하려고했습니다. 다른 질문은 여기에서 찾았지만,이 문제는 Hibernate Criteria 제한이나 JoinJ.Left 매개 변수를 지정하는 My ListJoin에서 시도한 LeftJoin으로 해결되는 것으로 보입니다. 내가 기준 API와 술어와 비교적 새로운 해요 언급 할

JPA CriteriaBuilder - How to use "IN" comparison operator

JPA2 Criteria-API: select... in (select from where)

:

여기에 링크가 이미 whitout 성공 솔루션을 테스트한다. 어쩌면 나는 JPA developpers에 경험이있는 분명한 분명한 것을 놓치고 있습니다.

도움을 주셔서 감사합니다.

답변

2

마지막으로 내 문제를 해결할 수있는 방법을 찾았습니다. 하위 엔티티의 부분 콜렉션 만 요청하면 데이터 무결성 측면에서 위험한 것으로 나타났습니다.get 내에서 자식 엔티티의 부분 콜렉션을 가진 부모 엔티티를 요청하기 위해 원격 서비스가 호출하면,이 부모 엔티티 객체는 수정 된 오퍼레이션을 반환 할 수 있으며, 이는 자식 엔티티의 제거 된 인스턴스에서 많은 "delete"호출을 발생시킵니다. 지속성 API는 이러한 누락 된 자식을 제거 된 관계로 간주합니다. 이는 원하지 않는 것입니다.

요청한 하위 엔티티의 부분 콜렉션을 포함하는 더미 전송 오브젝트를 작성하여이 더미 전송 오브젝트가 향후 수정 조작 호출에서 사용될 수 없도록하십시오. 상위 엔티티의 전체 버전은 "수정"목적으로 사용됩니다.

2

JPA 프로 바이더가 최대 절전 모드 일까? 하위 엔티티를 제거하는 대신 필터링 할 수있는 최대 절전 모드 필터를 고려 했습니까?하지만 필터 사용은 어떻게 든 이해하기 어렵습니다.

관련 문제