2014-10-10 7 views
12

(스프링 데이터 JPA 사용하기) 두 엔티티 Parent & Child과 OneToMany/ManyToOne 양방향 관계가있다. 내가 그렇게 같은 부모 개체에 @NamedEntityGraph을 추가하여 부모의 자녀에 대한 유형을 가져스프링 데이터 JPA + JpaSpecificationExecutor + EntityGraph

@Entity 
@NamedEntityGraph(name = "Parent.Offspring", attributeNodes = @NamedAttributeNodes("children")) 
public class Parent{ 
//blah blah blah 

@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY) 
Set<Child> children; 

//blah blah blah 
} 

주의하는 것이 LAZY이다. 이것은 의도적입니다. 개별 부모에게 질의 할 때 항상 아이들에게 열심히로드하고 싶지는 않습니다. 일반적으로 나는 네임드 엔티티 그래프를 사용하여 필요할 때 아이들을 열정적으로로드 할 수 있습니다. 하지만 .....

하나 이상의 부모를 쿼리하고 자녀를 열심히로드하려는 특정 상황이 있습니다. 이 외에도 프로그래밍 방식으로이 쿼리를 작성할 수 있어야합니다. 스프링 데이터는 동적 쿼리를 만들 수있는 JpaSpecificationExecutor을 제공하지만,이 특정 경우에는 열정적으로로드하는 자식을 위해 엔티티 그래프와 함께 사용하는 방법을 알 수 없습니다. 이것은 가능한가? 사양을 사용하는 많은 엔티티에 열의를 보내는 다른 방법이 있습니까?

@NoRepositoryBean 
public interface CustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> { 

    List<T> findAll(Specification<T> spec, EntityGraphType entityGraphType, String entityGraphName); 
    Page<T> findAll(Specification<T> spec, Pageable pageable, EntityGraphType entityGraphType, String entityGraphName); 
    List<T> findAll(Specification<T> spec, Sort sort, EntityGraphType entityGraphType, String entityGraphName); 
    T findOne(Specification<T> spec, EntityGraphType entityGraphType, String entityGraphName); 

}: 

는 또한 구현 만들 :

@NoRepositoryBean 
public class CustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CustomRepository<T, ID> { 

    private EntityManager em; 

    public CustomRepositoryImpl(Class<T> domainClass, EntityManager em) { 
     super(domainClass, em); 
     this.em = em; 
    } 

    @Override 
    public List<T> findAll(Specification<T> spec, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) { 
     TypedQuery<T> query = getQuery(spec, (Sort) null); 
     query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName)); 
     return query.getResultList(); 
    } 

    @Override 
    public Page<T> findAll(Specification<T> spec, Pageable pageable, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) { 
     TypedQuery<T> query = getQuery(spec, pageable.getSort()); 
     query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName)); 
     return readPage(query, pageable, spec); 
    } 

    @Override 
    public List<T> findAll(Specification<T> spec, Sort sort, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) { 
     TypedQuery<T> query = getQuery(spec, sort); 
     query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName)); 
     return query.getResultList(); 
    } 

    @Override 
    public T findOne(Specification<T> spec, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) { 
     TypedQuery<T> query = getQuery(spec, (Sort) null); 
     query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName)); 
     return query.getSingleResult(); 
    } 
} 

을 그리고 공장 만들 :

public class CustomRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> { 

    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { 
     return new CustomRepositoryFactory(entityManager); 
    } 

    private static class CustomRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory { 

     private EntityManager entityManager; 

     public CustomRepositoryFactory(EntityManager entityManager) { 
      super(entityManager); 
      this.entityManager = entityManager; 
     } 

     protected Object getTargetRepository(RepositoryMetadata metadata) { 
      return new CustomRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), entityManager); 
     } 

     protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { 
      // The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory 
      //to check for QueryDslJpaRepository's which is out of scope. 
      return CustomRepository.class; 
     } 
    } 

} 

을 그리고

+0

혹시이 질문에 대한 답을 찾으셨습니까 설정 repositoryFactoryBeanClass를 만들 필요가 없습니다? – Joep

+0

불행히도, 아니요. – Kerby

답변

9

이 솔루션은 이러한 기능을 구현하는 사용자 정의 저장소 인터페이스를 만드는 것입니다 기본 저장소 팩토리 bean을 새 bean으로 변경하십시오. 봄 부팅의 구성이 추가 :

@EnableJpaRepositories(
    basePackages = {"your.package"}, 
    repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class 
) 

더 많은 정보를 위해 사용자 정의 저장소에 대해 : http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-behaviour-for-all-repositories

+0

위대한 작품 @ 조피, 내게 두어 시간 작업을 저장. –

4

Joepie 응답이 오케이입니다

하지만 당신은 repositoryBaseClass

@EnableJpaRepositories(
    basePackages = {"your.package"}, 
    repositoryBaseClass = CustomRepositoryImpl.class) 
관련 문제