2013-08-18 63 views
20

我有如下一個實體類以獲取列的子集UserDemo只有idusername屬性填充?我需要使用分頁以及搜索。總之我想實現同樣的結果春數據JPA和Querydsl用豆/構造投影

Page<UserDemo> findAll(Predicate predicate, Pageable pageable); 

但UserDemo填充的有限的領域。

回答

28

看起來像自定義存儲庫實現是現在的方式,直到類似的東西在春季數據可用。

我已經通過http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.custom-implementations

了這是我實現它的工作原理。然而這將是很好直接在彈簧數據JPA具有可用此方法

步驟1:爲共享行爲中間體接口

public interface CustomQueryDslJpaRepository <T, ID extends Serializable> 
     extends JpaRepository<T, ID>, QueryDslPredicateExecutor<T> { 
    /** 
    * Returns a {@link org.springframework.data.domain.Page} of entities matching the given {@link com.mysema.query.types.Predicate}. 
    * This also uses provided projections (can be JavaBean or constructor or anything supported by QueryDSL 
    * @param constructorExpression this constructor expression will be used for transforming query results 
    * @param predicate 
    * @param pageable 
    * @return 
    */ 
    Page<T> findAll(FactoryExpression<T> factoryExpression, Predicate predicate, Pageable pageable); 
} 

步驟2:中間體接口的實現

public class CustomQueryDslJpaRepositoryImpl<T, ID extends Serializable> extends QueryDslJpaRepository<T, ID> 
     implements CustomQueryDslJpaRepository<T, ID> { 

    //All instance variables are available in super, but they are private 
    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 CustomQueryDslJpaRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) { 
     this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER); 
    } 

    public CustomQueryDslJpaRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, 
           EntityPathResolver resolver) { 

     super(entityInformation, entityManager); 
     this.path = resolver.createPath(entityInformation.getJavaType()); 
     this.builder = new PathBuilder<T>(path.getType(), path.getMetadata()); 
     this.querydsl = new Querydsl(entityManager, builder); 
    } 

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

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

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

第3步:創建一個定製存儲庫工廠以替換默認的

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

    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { 

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

     private EntityManager entityManager; 

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

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

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

第4步:使用自定義庫工廠

使用註釋

@EnableJpaRepositories(repositoryFactoryBeanClass=CustomQueryDslJpaRepositoryFactoryBean.class) 

或使用XML

<repositories base-package="com.acme.repository" factory-class="com.acme.CustomQueryDslJpaRepositoryFactoryBean" /> 

注意:不要將自定義庫界面並在同一個di中執行作爲基礎包的教區。如果要放置然後從掃描中排除,否則春天會盡量爲他們創造豆

使用範例

public interface UserDemoRepository extends CustomQueryDslJpaRepository<UserDemo, Long>{ 
} 

public class UserDemoService { 
    @Inject 
    UserDemoRepository userDemoRepository; 

    public Page<User> findAll(UserSearchCriteria userSearchCriteria, Pageable pageable) { 
     QUserDemo user = QUserDemo.userDemo; 
     return userDemoRepository.findAll(Projections.bean(UserDemo.class, user.id, user.username), UserPredicate.defaultUserSearch(userSearchCriteria), pageable); 
    } 

} 
+0

什麼是FactoryExpression是自定義類還是預定義的? –

+0

FactoryExpression是Querydsl中Projections的基類。 http://www.querydsl.com/static/querydsl/3.2.0/apidocs/com/mysema/query/types/FactoryExpression.html – Murali

+0

我得到一個'引起:org.springframework.data.mapping.PropertyReferenceException:No找到類型'的財產找到時,我嘗試了這一點。這是爲什麼? 當然代表我的實體類型。 –

3

對於較新版本的春天的數據,我不能讓接受的答案沒有擊中問題需要解決,但發現下去從Spring數據文件的路徑,通過修改這個問題的答案如下做工作:

1.倉庫接口

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

    <PROJ> Page<PROJ> customFindWithProjection(FactoryExpression<PROJ> factoryExpression, Predicate predicate, Pageable pageable); 
} 

2。該倉庫實現

public class QueryDslJpaEnhancedRepositoryImpl<T, ID extends Serializable> extends QueryDslJpaRepository<T, ID> 
     implements QueryDslPredicateAndProjectionExecutor<T, ID> { 

    //All instance variables are available in super, but they are private 
    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 QueryDslJpaEnhancedRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) { 
     this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER); 
    } 

    public QueryDslJpaEnhancedRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, 
           EntityPathResolver resolver) { 

     super(entityInformation, entityManager, resolver); 
     this.path = resolver.createPath(entityInformation.getJavaType()); 
     this.builder = new PathBuilder<T>(path.getType(), path.getMetadata()); 
     this.querydsl = new Querydsl(entityManager, builder); 
    } 

    @Override 
    public <PROJ> Page<PROJ> customFindWithProjection(FactoryExpression<PROJ> factoryExpression, Predicate predicate, Pageable pageable) { 
     JPQLQuery countQuery = createQuery(predicate); 
     JPQLQuery query = querydsl.applyPagination(pageable, createQuery(predicate)); 

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

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

3.設置默認存儲庫實現

@EnableJpaRepositories(
    repositoryBaseClass=QueryDslJpaEnhancedRepositoryImpl.class, 
    basePackageClasses=SomeRepository.class) 
+0

你有這個地方的代碼基地,是PROJ意味着我的投影界面,我得到一些編譯錯誤,請分享任何github網站或任何我可以參考的地方... – surya

+0

實際上,我實施後,雖然dsl部分作品,我得到的結果不是投影,但整個對象。所以回到原點..請讓我知道,如果你有示例代碼的地方查詢dsl +投影 – surya

+0

而我在你的存儲庫中使用1.4.0.RELEASE彈簧啓動版本 – surya

1

春天數據的當前版本(1.11.1)和QueryDSL(4),你必須改變customFindWithProjection方法實現這樣的:

@Override 
public <PROJ> Page<PROJ> customFindWithProjection(FactoryExpression<PROJ> factoryExpression, Predicate predicate, Pageable pageable) { 

    final JPQLQuery<?> countQuery = createCountQuery(predicate); 
    JPQLQuery<PROJ> query = querydsl.applyPagination(pageable, createQuery(predicate).select(factoryExpression)); 

    long total = countQuery.fetchCount(); 
    List<PROJ> content = pageable == null || total > pageable.getOffset() ? query.fetch() : Collections.<PROJ> emptyList(); 

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

代碼的其餘部分保持不變。