以下のようなエンティティクラスがあります。
@Entity
public class UserDemo implements Serializable {
@Id
private Long id;
private String username;
private String createdBy;
@Version
private int version;
/***
*
* Getters and setters
*/
}
Spring Data JPAとQuerydslを使用して、id
プロパティとusername
プロパティのみが入力されたserDemoのページをフェッチするにはどうすればよいですか?ページングと検索を使用する必要があります。要するに私は同じ結果を達成したいと思います
Page<UserDemo> findAll(Predicate predicate, Pageable pageable);
serDemoの限られたフィールドが入力されています。
カスタムリポジトリの実装は、今のところ、春のデータで同様のものが利用可能になるまで進む方法のようです。
これが機能する私の実装です。ただし、このメソッドをSpring-Data-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" />
注:カスタムリポジトリインターフェースと実装をbase-packageと同じディレクトリに配置しないでください。配置している場合はスキャンから除外します。そうでない場合、SpringはそれらのBeanを作成しようとします
使用例
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);
}
}
Spring Dataの最近のバージョンでは、問題にぶつからずに承認された回答を得ることができませんでしたが、Spring Dataドキュメントからルートをたどると、その回答を次のように修正することで機能することがわかりました。
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);
}
}
。デフォルトのリポジトリ実装の設定
@EnableJpaRepositories(
repositoryBaseClass=QueryDslJpaEnhancedRepositoryImpl.class,
basePackageClasses=SomeRepository.class)
Spring Data(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);
}
残りのコードは同じままです。
(非常に醜く非効率的ではありますが)回避策として、エンティティを含む通常のPage
をリポジトリから取得し、次のようにコントローラーのプロジェクションに手動でマッピングしました。
@GetMapping(value = "/columns")
public Page<ColumnProjection> getColumns(@QuerydslPredicate(root = Column.class) final Predicate predicate,
final Pageable pageable) {
Page<Column> filteredColumns = columnRepository.findAll(predicate, pageable);
List<ColumnProjection> filteredColumnProjections = new ArrayList<>();
filteredColumns.forEach(c -> filteredColumnProjections.add(new ColumnProjectionImpl(c)));
return new PageImpl<>(filteredColumnProjections, pageable, filteredColumnProjections.size());
}
ここで、ColumnProjectionImpl
は、ColumnProjection
インターフェースを実装するクラスです。
これは、既存のColumnRepositoryを適応させる必要がない間、思いつくことができる最も簡単なソリューションでした。
私は同じ問題に自分で遭遇しました。つまり、カスタムリポジトリファクトリBeanを指定する必要があります。これは、カスタムリポジトリを別の「フラグメント」として使用するように指示します。したがって、factory.getRepositoryFragmentsをオーバーライドして、カスタムプロジェクション述語の実装を含めました(IMHOは問題の問題を解決します タイプのカスタムプロパティが見つかりません…カスタムSpring Dataリポジトリ )。
以前のすべての回答に基づいて更新されたコード:
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));
ほんの少しのコードで同じ結果を得ることができました。
public class Queryable<T> extends QuerydslJpaPredicateExecutor<T> {
private static final EntityPathResolver resolver = SimpleEntityPathResolver.INSTANCE;
private final Querydsl querydsl;
public Queryable(Class<T> domainClass, EntityManager entityManager) {
this(JpaEntityInformationSupport.getEntityInformation(domainClass, entityManager),
entityManager);
}
private Queryable(JpaEntityInformation<T, ?> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager, resolver, null);
EntityPath<T> path = resolver.createPath(entityInformation.getJavaType());
PathBuilder<?> builder = new PathBuilder<>(path.getType(), path.getMetadata());
this.querydsl = new Querydsl(entityManager, builder);
}
public Page<T> findAll(Expression<T> expression, Predicate predicate, Pageable pageable) {
JPQLQuery<?> countQuery = createQuery(predicate);
JPQLQuery<T> query = querydsl.applyPagination(pageable,
createQuery(predicate).select(expression));
List<T> dtos = query.fetch();
return PageableExecutionUtils.getPage(dtos, pageable, countQuery::fetchCount);
}
}
使用法:
@Repository
@Transactional
class UserDemoRepository
private static final QUserDemo q = QUserDemo.userDemo;
private static final QBean<UserDemo> PROJECTION = Projections.bean(UserDemo.class,
q.id, q.username);
@PersistenceContext
private EntityManager entityManager;
public Page<UserDemo> findAll(Predicate predicate, Pageable pageable) {
return new Queryable<UserDemo>(UserDemo.class, entityManager)
.findAll(PROJECTION, predicate, pageable);
}
}
1。CustomJpaRepositoryFactoryBean
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 CustomJpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {
public CustomJpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new CustomJpaRepositoryFactory(entityManager);
}
}
2。CustomJpaRepositoryFactory
import static org.springframework.data.querydsl.QueryDslUtils.QUERY_DSL_PRESENT;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.QueryDslJpaRepository;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryMetadata;
public class CustomJpaRepositoryFactory extends JpaRepositoryFactory {
public CustomJpaRepositoryFactory(EntityManager entityManager) {
super(entityManager);
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
if(QUERY_DSL_PRESENT) {
Class<?> repositoryInterface = metadata.getRepositoryInterface();
if(CustomQueryDslPredicateExecutor.class.isAssignableFrom(repositoryInterface)) {
return CustomQueryDslJpaRepository.class;
} else if(QueryDslPredicateExecutor.class.isAssignableFrom(repositoryInterface)) {
return QueryDslJpaRepository.class;
}
}
return SimpleJpaRepository.class;
}
}
。CustomQueryDslJpaRepository
import Java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.QueryDslJpaRepository;
import org.springframework.data.jpa.repository.support.Querydsl;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
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.Projections;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.JPQLQuery;
public class CustomQueryDslJpaRepository<T, ID extends Serializable> extends QueryDslJpaRepository<T, ID> implements CustomQueryDslPredicateExecutor<T> {
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
private final Querydsl querydsl;
public CustomQueryDslJpaRepository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
}
public CustomQueryDslJpaRepository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, EntityPathResolver resolver) {
super(entityInformation, entityManager, resolver);
EntityPath<T> path = resolver.createPath(entityInformation.getJavaType());
PathBuilder<T> builder = new PathBuilder<T>(path.getType(), path.getMetadata());
this.querydsl = new Querydsl(entityManager, builder);
}
public <DTO> Page<DTO> findAll(Predicate predicate, Pageable pageable, FactoryExpression<DTO> factoryExpression) {
JPQLQuery<DTO> query = createQuery(predicate).select(factoryExpression);
querydsl.applyPagination(pageable, query);
querydsl.applySorting(pageable.getSort(), query);
QueryResults<DTO> queryResults = query.fetchResults();
return new PageImpl<>(queryResults.getResults(), pageable, queryResults.getTotal());
}
}
4。CustomQueryDslPredicateExecutor
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.querydsl.QueryDslPredicateExecutor;
public interface CustomQueryDslPredicateExecutor<T> extends QueryDslPredicateExecutor<T> {
<DTO> Page<DTO> findAll(Predicate predicate, Pageable pageable, FactoryExpression<DTO> factoryExpression);
}
5。例
@EnableJpaRepositories(
...
repositoryFactoryBeanClass = CustomJpaRepositoryFactoryBean.class
)
public interface ProductRepository extends JpaRepository<Product, Long> implements CustomQueryDslPredicateExecutor<Product> {
}