私はちょうど同じ問題に遭遇しました。つまり、カスタム リポジトリ ファクトリ Bean を指定して、カスタム リポジトリを別の「フラグメント」として使用するように指示する必要があります。そこで、factory.getRepositoryFragments をオーバーライドして、カスタム プロジェクション述語の実装を含めました (IMHO の質問No property found for type… custom Spring Data repositoryの問題を解決します)。
以前のすべての回答に基づいて更新されたコード:
1.QuerydslPredicateProjectionRepositoryFactory
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryComposition;
import org.springframework.data.repository.core.support.RepositoryFragment;
import javax.persistence.EntityManager;
import java.io.Serializable;
import static org.springframework.data.querydsl.QuerydslUtils.QUERY_DSL_PRESENT;
public class QuerydslPredicateProjectionRepositoryFactory extends JpaRepositoryFactory {
private final EntityManager entityManager;
private EntityPathResolver entityPathResolver;
public QuerydslPredicateProjectionRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
this.entityPathResolver = SimpleEntityPathResolver.INSTANCE;
}
@Override
protected RepositoryComposition.RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
RepositoryComposition.RepositoryFragments fragments = super.getRepositoryFragments(metadata);
boolean isQueryDslRepository = QUERY_DSL_PRESENT
&& QuerydslPredicateProjectionRepository.class.isAssignableFrom(metadata.getRepositoryInterface());
if (isQueryDslRepository) {
JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
Object querydslFragment = getTargetRepositoryViaReflection(QuerydslPredicateProjectionRepositoryImpl.class, entityInformation,
entityManager, entityPathResolver, null);
fragments = fragments.append(RepositoryFragment.implemented(querydslFragment));
}
return fragments;
}
}
2.QuerydslPredicateProjectionRepositoryFactoryBean
import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
public class QuerydslPredicateProjectionRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {
public QuerydslPredicateProjectionRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new QuerydslPredicateProjectionRepositoryFactory(entityManager);
}
}
3.QuerydslPredicateProjectionRepositoryここで、プロジェクションなどを使用する新しいメソッドを追加します...
import com.querydsl.core.types.FactoryExpression;
import com.querydsl.core.types.Predicate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.util.List;
public interface QuerydslPredicateProjectionRepository<T> {
<Projection> Page<Projection> findAll(Predicate predicate, Pageable pageable, FactoryExpression<Projection> factoryExpression);
<Projection> List<Projection> findAll(Predicate predicate, Sort sort, FactoryExpression<Projection> factoryExpression);
<Projection> List<Projection> findAll(Predicate predicate, FactoryExpression<Projection> factoryExpression);
}
4.QuerydslPredicateProjectionRepositoryImplここで、リポジトリ インターフェイス メソッドを実装します。
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.EntityPath;
import com.querydsl.core.types.FactoryExpression;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.JPQLQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.support.CrudMethodMetadata;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.Querydsl;
import org.springframework.data.jpa.repository.support.QuerydslJpaPredicateExecutor;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
import javax.persistence.EntityManager;
import java.util.List;
public class QuerydslPredicateProjectionRepositoryImpl<T> extends QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateProjectionRepository<T> {
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
private final Querydsl querydsl;
public QuerydslPredicateProjectionRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
}
public QuerydslPredicateProjectionRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager, EntityPathResolver resolver) {
super(entityInformation, entityManager, resolver, null);
EntityPath<T> path = resolver.createPath(entityInformation.getJavaType());
PathBuilder<T> builder = new PathBuilder<T>(path.getType(), path.getMetadata());
this.querydsl = new Querydsl(entityManager, builder);
}
public QuerydslPredicateProjectionRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager, EntityPathResolver resolver, CrudMethodMetadata metadata) {
super(entityInformation, entityManager, resolver, metadata);
EntityPath<T> path = resolver.createPath(entityInformation.getJavaType());
PathBuilder<T> builder = new PathBuilder<T>(path.getType(), path.getMetadata());
this.querydsl = new Querydsl(entityManager, builder);
}
@Override
public <Projection> List<Projection> findAll(Predicate predicate, FactoryExpression<Projection> factoryExpression) {
return createQuery(predicate).select(factoryExpression).fetch();
}
@Override
public <Projection> List<Projection> findAll(Predicate predicate, Sort sort, FactoryExpression<Projection> factoryExpression) {
JPQLQuery<Projection> query = createQuery(predicate).select(factoryExpression);
querydsl.applySorting(sort, query);
return query.fetch();
}
@Override
public <Projection> Page<Projection> findAll(Predicate predicate, Pageable pageable, FactoryExpression<Projection> factoryExpression) {
JPQLQuery<Projection> query = createQuery(predicate).select(factoryExpression);
querydsl.applyPagination(pageable, query);
querydsl.applySorting(pageable.getSort(), query);
QueryResults<Projection> queryResults = query.fetchResults();
return new PageImpl<>(queryResults.getResults(), pageable, queryResults.getTotal());
}
}
5.エンティティの例
@Entity
public class Example extends Serializable{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@Column
private String name;
@Column
private String surname;
@Column
private Integer year;
public Example() {
}
public Long getId() {return id;}
public void setId(Long id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String getSurname() {return surname;}
public void setSurname(String surname) {this.surname= surname;}
public Integer getYear() {return year;}
public void setSurname(Integer year) {this.year= year;}
}
6.レポジトリの例
@Repository
public interface ExampleRepository extends JpaRepository<Example, Long>, QuerydslPredicateProjectionRepository<Example> { }
7.使用
構成例:
@EnableJpaRepositories(repositoryFactoryBeanClass = QuerydslPredicateProjectionRepositoryFactoryBean.class)
典型的な使用法:
//get list of entities only with year field value set - memory consuming
List<Example> years = repository.findAll(predicate, Projections.fields(Example.class, QExample.example.year));
//get list of tuples - looks nicer - less memory consuming
List<Tuple> years = repository.findAll(predicate, Projections.tuple(QExample.example.year));
//get list of integers - nice :)
List<Integer> years = repository.findAll(predicate, Projections.constructor(Integer.class, QExample.example.year));