I have an entity class as below:
@Entity
public class UserDemo implements Serializable {
    @Id
    private Long id;
    private String username;
    private String createdBy;
    @Version
    private int version;
    /***
     *
     * Getters and setters
     */
}
Using Spring Data JPA and Querydsl how do I fetch a page of UserDemo with only id and username properties populated? I need to use paging as well as searching. In short I would like to achieve the same result as
Page<UserDemo> findAll(Predicate predicate, Pageable pageable);
but with limited field of UserDemo populated.
Querydsl is an extensive Java framework, which helps with creating and running type-safe queries in a domain specific language that is similar to SQL. In this article we'll explore Querydsl with the Java Persistence API.
Actually, the difference between findallBy and findby, is that : findAllBy returns a Collection but findBy returns Optional. so it's preferable to write List findAllBy instead of writing List findBy (but it will work also :p). and to write Optional findBy instead of Optional findAllBy.
Querydsl is a framework that enables the construction of statically typed SQL-like queries through its fluent API. Spring Data modules offer integration with Querydsl through QuerydslPredicateExecutor .
In order to define SQL to execute for a Spring Data repository method, we can annotate the method with the @Query annotation — its value attribute contains the JPQL or SQL to execute. The @Query annotation takes precedence over named queries, which are annotated with @NamedQuery or defined in an orm.xml file.
Looks like custom repository implementation is the way to go for now until something similar available in spring data.
I have gone through http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.custom-implementations
Here is my implementation which works. However it would be good to have this method available directly in Spring-Data-JPA
Step 1: Intermediate interface for shared behavior
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);
}
Step 2: Implementation of intermediate interface
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);
    }
}
Step 3: Create a custom repository factory to replace the default
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;
        }
    }
}
Step 4: Use the custom repository factory
Using annotation
@EnableJpaRepositories(repositoryFactoryBeanClass=CustomQueryDslJpaRepositoryFactoryBean.class)
OR using XML
<repositories base-package="com.acme.repository"  factory-class="com.acme.CustomQueryDslJpaRepositoryFactoryBean" />
Note: Don't place custom repository interface and implementation in the same directory as base-package. If you are placing then exclude them from scanning otherwise spring will try to create beans for them
Sample usage
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);
    }
}
For more recent versions of Spring Data, I couldn't get the accepted answer to work without hitting issues, but found that going down the route from the Spring Data docs, does work by revising that answer as follows:
1. The repository interface
@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. The repository implementation
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. Setting the default repository implementation
@EnableJpaRepositories(
    repositoryBaseClass=QueryDslJpaEnhancedRepositoryImpl.class,
    basePackageClasses=SomeRepository.class)
For the current versions of Spring Data (1.11.1) and QueryDSL (4), you have to change the customFindWithProjection method implementation like this:
@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);
}
The rest of the code remains the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With