【问题标题】:How can I use Spring's pagination (using Pageable) while writing a dynamic query using QueryDSL?如何在使用 QueryDSL 编写动态查询时使用 Spring 的分页(使用 Pageable)?
【发布时间】:2017-07-18 02:21:37
【问题描述】:

我正在尝试通过 QueryDSL 使用分页 - 使用 com.mysema.querydsl 包。

我所有的 Querydsl 查询类型都是这样的 -

@Generated("com.mysema.query.codegen.EntitySerializer")
public class QCountry extends EntityPathBase<Country> {...}

目前,我的存储库实现类看起来像这样 -

     @Override
            public Page<Country> findPaginatedCountries(String country, Optional<String> status, Pageable pageable) {

                QCountry qCountry= QCountry.someObject;
                QActiveCountry qActiveCountry = QActiveCountry.activeCountry;

               JPAQuery jpaQuery = new JPAQuery(entityManager);

                QueryBase queryBase = jpaQuery.from(qCountry).innerJoin(qActiveCountry).fetch()
                        .where(qCountry.codeLeft.country.upper().eq(country.toUpperCase()))
                        .where(qCountry.codeRight.country.upper().eq(country.toUpperCase()));



                if(status.isPresent()){
                    queryBase = queryBase.where(qActiveCountry.id(qCountry.active.id))
                            .where(qActiveCountry.status.upper().eq(status.get().toUpperCase()));
                }
.......}

现在,我希望这个动态查询返回一个分页响应。我想使用 Spring 的分页来做到这一点,而不是手动设置偏移量、大小等。

我知道我可以使用 QueryDslRepositorySupport 类 - 在这里实现 - https://github.com/keke77/spring-data-jpa-sample/blob/master/spring-data-jpa/src/main/java/com/gmind7/bakery/employee/EmployeeRepositoryImpl.java

来自上述链接的示例代码 -

@Override
    public Page<Employees> QFindByOfficeCode(long officeCode, Pageable pageable) {
        //JPAQuery query = new JPAQuery(em);
        JPQLQuery query = from(QEmployees.employees).where(QEmployees.employees.officeCode.eq(officeCode));
        query = super.getQuerydsl().applyPagination(pageable, query);
        SearchResults<Employees> entitys = query.listResults(QEmployees.employees);
        return new PageImpl<Employees>(entitys.getResults(), pageable, entitys.getTotal());
    }      

但是,要做到这一点 -

  1. 我需要将 JPQLQuery 对象传递给 applyPagination 方法。如何在不更改代码的情况下做到这一点(当然,存储库类将扩展 QueryDslRepositorySupport 类)。目前,如您所见,我正在使用 JPAQuery。

或

  1. 我可能需要更改我的 QueryDSL 类型,让它们扩展 EntityPath 而不是 EntityPathBase,以便我可以使用 JPQLQuery.from() 生成查询,然后使用需要 JPQLQuery 对象的 applyPagination 方法。但是,我的 Q 类正在扩展 EntityPathBase 类。我应该使用 com.querydsl 包而不是 com.mysemsa.querydsl 包来生成查询类型吗?

或

  1. 其他选项是使用以下 - http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/querydsl/QueryDslPredicateExecutor.html#findAll-com.querydsl.core.types.Predicate-org.springframework.data.domain.Pageable-

下面的代码sn-p -

 Page<T> page = QueryDslPredicateExecutor.findAll(org.springframework.data.querydsl.Predicate predicate, Pageable pageable)

但是,我在两个表之间进行连接,然后使用 where 子句过滤结果(如您在上面的代码中所见)。如何在上面的 findAll 方法中传递谓词对象?不知道如何在其中包含一个联接。

如果问题不清楚,请告诉我,我可以添加更多细节。

编辑:Country 和 ActiveCountry 之间存在多对一的关系。 Country 类有一个 ActiveCountry 引用。我们必须在两个 id 之间进行连接。 Country 可能有 null ActiveCountry。因此,我们需要一个内部连接——只有活动国家的非空值

@ManyToOne
@JoinColumn(name="id")
ActiveCountry active;

【问题讨论】:

  • 有人对此有什么意见吗?
  • 我正在努力解决同样的问题。你有没有找到解决办法?谢谢!
  • 我认为您的问题没有问题。如果您需要JPAQuery 来进行连接,请使用Querydsl#createQuery(您可以使用QuerydslRepositorySupport#getQuerydsl 获得Querydsl 对象)。还是我错过了什么?

标签: spring pagination spring-data-jpa querydsl


【解决方案1】:

第一步:用@QueryEntity注解实体类

@Entity
@QueryEntity
public class Country {}

这似乎已经解决,因为问题显示Q 类。

第 2 步:让存储库接口扩展 QueryDslPredicateExecutor

public interface CountryRepository
                 extends PagingAndSortingRepository<Country, Long>
                         , QueryDslPredicateExecutor<Country> {
}

第三步:调用QueryDslPredicateExecutor提供的Page&lt;T&gt; findAll(Predicate query, Pageable page)方法

public Page<Country> getCountries(String country, Optional<String> status, Pageable page) {
  QCountry root = QCountry.country;

  BooleanExpression query = root.codeLeft.country.equalsIgnoreCase(country);
  query = query.and(root.codeRight.country.equalsIgnoreCase(country));

  if (status.isPresent()) {
    query = query.and(root.active.status.equalsIgnoreCase(status));
  }

  return countryRepository.findAll(query, page);
}

【讨论】:

  • 感谢您的回复。然而,问题是能够在构建 Predicate 或 BooleanExpression 时连接两个表。你能编辑你对如何做到这一点的回应吗?谢谢
  • @Righto,请将实体类的最短代码添加到您的问题中。不了解类之间的关系就很难形成查询。
  • 所以基本上,Country 和 ActiveCountry 之间存在多对一的关系。
  • 我确实是建设性的。我已经在我的代码中明确说明了“innerjoin”。我会感谢这里有耐心继续对话而不是像你刚才那样生气和威胁的人。无论如何,谢谢你的帮助。
  • 当我按照这个例子进行操作时,Hibernate 会无缘无故地生成交叉连接。我需要控制整个查询...
猜你喜欢
  • 2012-07-25
  • 2014-06-02
  • 1970-01-01
  • 2015-12-03
  • 2020-11-13
  • 2017-10-31
  • 1970-01-01
  • 2020-03-02
  • 1970-01-01
相关资源
最近更新 更多