Spring Данные JPA и Querydsl для извлечения подмножества столбцов с использованием bean/проекции конструктора
У меня есть класс сущности, как показано ниже:
@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, как я могу получить страницу UserDemo только с заполненными свойствами id
и username
? Мне нужно использовать подкачку, а также поиск. Короче говоря, я хотел бы достичь того же результата, что и
Page<UserDemo> findAll(Predicate predicate, Pageable pageable);
но с ограниченным полем UserDemo.
Ответы
Ответ 1
Похоже, что реализация пользовательских репозиториев - это путь, пока не появится что-то подобное в данных spring.
Я прошел http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.custom-implementations
Вот моя работа, которая работает. Однако было бы неплохо, если бы этот метод был доступен непосредственно в 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. Создание пользовательского репозитория factory для замены стандартного
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. Использование пользовательского репозитория factory
Использование аннотации
@EnableJpaRepositories(repositoryFactoryBeanClass=CustomQueryDslJpaRepositoryFactoryBean.class)
ИЛИ используя XML
<repositories base-package="com.acme.repository" factory-class="com.acme.CustomQueryDslJpaRepositoryFactoryBean" />
Примечание. Не размещайте пользовательский интерфейс и реализацию репозитория в том же каталоге, что и базовый пакет. Если вы помещаете, то исключайте их из сканирования, иначе spring попытается создать beans для них
Использование примера
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);
}
}
Ответ 2
Для более поздних версий 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);
}
}
3. Настройка реализации репозитория по умолчанию
@EnableJpaRepositories(
repositoryBaseClass=QueryDslJpaEnhancedRepositoryImpl.class,
basePackageClasses=SomeRepository.class)
Ответ 3
Для текущих версий 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);
}
Остальная часть кода остается прежней.
Ответ 4
Как (хотя и очень уродливое и неэффективное) обходное решение, я просто получил обычную 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.
Ответ 5
Я сам столкнулся с той же проблемой. Короче говоря - мы должны указать пользовательский репозиторий фабричного компонента, который указывает использовать наше пользовательское репо в качестве еще одного "фрагмента". Поэтому я переопределил factory.getRepositoryFragments для включения пользовательской реализации предиката проекции (ИМХО это решает проблему в вопросе Не найдено свойство для типа… настраиваемый репозиторий 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));
Ответ 6
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;
}
}
3. 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> {
}
Ответ 7
Я смог достичь того же результата с помощью небольшого кода.
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
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);
}
}
(вдохновлено fooobar.com/info/18004118/...)