2013-05-08 8 views
7

私はSpring Data JPAプロジェクトのQueryDslPredicateExecutorを使用しています。私は怠惰な関係を熱心に取得する必要があります。リポジトリ・インタフェースでネイティブのJPA-QL問合せを使用することも、JPAQLQueryをQuery DSLから使用することもできますが、これが可能であれば将来のニーズに合わせて問合せを作成することができます。QueryDSLのPredicate APIを使用して怠惰な関係を取得することができますか?

+0

これが可能であればどういう意味ですか? 'QueryDslPredicateExecutor'は、Querydslの機能の小さなサブセットを提供します。あなた自身でより多くの質問を書く必要があります。 –

+0

ええ、私はそれを避ける方法を考えようとしていましたが、プレディケートAPIを使用してより複雑なクエリを構築し、自由に関係をフェッチしたり、他の述語を追加することができ、リポジトリインタフェース内の特定の目的の注釈付きクエリを使用します。 –

答えて

11

私はPredicatesとQueryDslPredicateExecutorを使用しているときにコレクションをフェッチしなければならない同様の問題がありました。

私が行ったのは、カスタムリポジトリの実装を作成して、フェッチする必要があるエンティティを定義できるメソッドを追加することでした。

がここにコードの量によってひるむことはいけない、それは実際には非常に簡単です、あなたはあなたのアプリケーションに

を、それを使用することは非常にいくつかの変更を行う必要がありますこれは、カスタムのインタフェースでありますリポジトリ

@NoRepositoryBean 
public interface JoinFetchCapableRepository<T, ID extends Serializable> extends  JpaRepository<T, ID>, QueryDslPredicateExecutor<T> { 

    Page<T> findAll(Predicate predicate, Pageable pageable, JoinDescriptor... joinDescriptors); 
} 

JoinDescriptor

public class JoinDescriptor { 
    public final EntityPath path; 
    public final JoinType type; 

    private JoinDescriptor(EntityPath path, JoinType type) { 
     this.path = path; 
     this.type = type; 
    } 

    public static JoinDescriptor innerJoin(EntityPath path) { 
     return new JoinDescriptor(path, JoinType.INNERJOIN); 
    } 

    public static JoinDescriptor join(EntityPath path) { 
     return new JoinDescriptor(path, JoinType.JOIN); 
    } 

    public static JoinDescriptor leftJoin(EntityPath path) { 
     return new JoinDescriptor(path, JoinType.LEFTJOIN); 
    } 

    public static JoinDescriptor rightJoin(EntityPath path) { 
     return new JoinDescriptor(path, JoinType.RIGHTJOIN); 
    } 

    public static JoinDescriptor fullJoin(EntityPath path) { 
     return new JoinDescriptor(path, JoinType.FULLJOIN); 
    } 
} 
カスタムリポジトリの210

実装

public class JoinFetchCapableRepositoryImpl <T, ID extends Serializable> extends QueryDslJpaRepository<T, ID> implements JoinFetchCapableRepository<T, ID> { 

    private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE; 

    private final EntityPath<T> path; 
    private final PathBuilder<T> builder; 
    private final Querydsl querydsl; 

    public JoinFetchCapableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) { 
     this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER); 
    } 

    public JoinFetchCapableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, EntityPathResolver resolver) { 
     super(entityInformation, entityManager, resolver); 
     this.path = resolver.createPath(entityInformation.getJavaType()); 
     this.builder = new PathBuilder<>(path.getType(), path.getMetadata()); 
     this.querydsl = new Querydsl(entityManager, builder); 
    } 

    @Override 
    public Page<T> findAll(Predicate predicate, Pageable pageable, JoinDescriptor... joinDescriptors) { 
     JPQLQuery countQuery = createQuery(predicate); 
     JPQLQuery query = querydsl.applyPagination(pageable, createFetchQuery(predicate, joinDescriptors)); 

     Long total = countQuery.count(); 
     List<T> content = total > pageable.getOffset() ? query.list(path) : Collections.<T> emptyList(); 

     return new PageImpl<>(content, pageable, total); 
    } 

    protected JPQLQuery createFetchQuery(Predicate predicate, JoinDescriptor... joinDescriptors) { 
     JPQLQuery query = querydsl.createQuery(path); 
     for(JoinDescriptor joinDescriptor: joinDescriptors) 
      join(joinDescriptor, query); 
     return query.where(predicate); 
    } 

    private JPQLQuery join(JoinDescriptor joinDescriptor, JPQLQuery query) { 
     switch(joinDescriptor.type) { 
      case DEFAULT: 
       throw new IllegalArgumentException("cross join not supported"); 
      case INNERJOIN: 
       query.innerJoin(joinDescriptor.path); 
       break; 
      case JOIN: 
       query.join(joinDescriptor.path); 
       break; 
      case LEFTJOIN: 
       query.leftJoin(joinDescriptor.path); 
       break; 
      case RIGHTJOIN: 
       query.rightJoin(joinDescriptor.path); 
       break; 
      case FULLJOIN: 
       query.fullJoin(joinDescriptor.path); 
       break; 
     } 
     return query.fetch(); 
    } 
} 

工場、それはこのファクトリを使用していますので、QueryDslJpaRepository

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

    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { 

     return new JoinFetchCapableQueryDslJpaRepositoryFactory(entityManager); 
    } 
    private static class JoinFetchCapableQueryDslJpaRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory { 

     private EntityManager entityManager; 

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

     protected Object getTargetRepository(RepositoryMetadata metadata) { 
      return new JoinFetchCapableRepositoryImpl<>(getEntityInformation(metadata.getDomainType()), entityManager); 
     } 

     protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { 
      return JoinFetchCapableRepository.class; 
     } 
    } 
} 

最後のステップは、JPAの設定を変更することで、デフォルトの交換、カスタムリポジトリを作成しますデフォルトのものの代わりに

<jpa:repositories base-package="com.mycompany.repository" 
         entity-manager-factory-ref="entityManagerFactory" 
         factory-class="com.mycompany.utils.spring.data.JoinFetchCapableQueryDslJpaRepositoryFactoryBean" /> 

そして、あなたはこのようなあなたのサービス層からそれを使用することができます。

public Page<ETicket> list(ETicketSearch eTicket, Pageable pageable) { 
    return eticketRepository.findAll(like(eTicket), pageable, JoinDescriptor.leftJoin(QETicket.eTicket.order)); 
} 

をJoinDescriptorを使用することにより、あなたはあなたのサービスのニーズに基づいて、参加したいものを指定することができるようになります。

私はMuraliの応答のおかげでこれを行うことができました:Spring Data JPA and Querydsl to fetch subset of columns using bean/constructor projectionご覧ください。

+1

あなたの答えをありがとう。私はCriteriaのアプローチで作業を終えましたが、テストするための小さなプロジェクトでこのアプローチをテストします。あなたの努力に感謝します... –

+0

こんにちは、答えに感謝します。 EntityPathだけでなくonetomany(つまりSetPath)を含めるようにJoinDescriptorを拡張することは可能ですか? –

+0

@AngelVillalain「Criteriaのアプローチで作業しましたが、どのように機能させるのか説明できますか? – Pranjal