2014-10-10 38 views
12

(Sử dụng dữ liệu Spring JPA) Tôi có hai thực thể Parent & Child với mối quan hệ hai hướng OneToMany/ManyToOne giữa chúng. Tôi thêm một @NamedEntityGraph để công ty mẹ như sau:Dữ liệu mùa xuân 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 
} 

Chú ý rằng các loại cho trẻ em của phụ huynh lấy là lười. Đây là mục đích. Tôi không luôn luôn muốn háo hức tải trẻ em khi tôi đang truy vấn một phụ huynh riêng lẻ. Thông thường tôi có thể sử dụng biểu đồ thực thể có tên của tôi để mong muốn tải các trẻ em theo yêu cầu, do đó, để nói chuyện. Nhưng .....

Có một tình huống cụ thể mà tôi muốn truy vấn cho một hoặc nhiều phụ huynh và mong muốn tải con cái của họ. Thêm vào đó tôi cần để có thể xây dựng truy vấn này theo lập trình. Dữ liệu mùa xuân cung cấp JpaSpecificationExecutor cho phép một người xây dựng các truy vấn động, nhưng tôi không thể tìm ra cách sử dụng nó cùng với biểu đồ thực thể để tải trẻ em háo hức trong trường hợp cụ thể này. Điều này thậm chí có thể? Có cách nào khác để háo hức tải 'toMany thực thể bằng cách sử dụng thông số kỹ thuật?

+0

Bạn đã bao giờ tìm thấy câu trả lời cho câu hỏi này? – Joep

+0

Thật không may, không. – Kerby

Trả lời

9

Giải pháp là để tạo ra một giao diện kho lưu trữ tùy chỉnh mà thực hiện các tính năng:

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

}: 

Cũng tạo một thực hiện:

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

Và tạo một nhà máy:

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

} 

Và thay đổi bean nhà máy kho mặc định thành bean mới, ví dụ trong khởi động mùa xuân thêm video này vào cấu hình:

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

Đối với thông tin thêm về kho tùy chỉnh: http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-behaviour-for-all-repositories

+0

Công việc tuyệt vời @Joepie, đã lưu tôi một vài giờ làm việc. –

4

Câu trả lời Joepie là O.K.

nhưng bạn không cần phải tạo ra repositoryFactoryBeanClass, thiết lập repositoryBaseClass

@EnableJpaRepositories(
    basePackages = {"your.package"}, 
    repositoryBaseClass = CustomRepositoryImpl.class) 
Các vấn đề liên quan