将Spring分页应用于动态创建的查询

时间:2019-03-13 16:19:28

标签: java spring jpa spring-data-jpa

如果我有一个Spring存储库,则可以通过以下方式定义一个方法来获得分页结果(例如):

@Query("<some JPAQL here>")
Page<Person> findBySomething(String foo, String bar, Pageable pageable);

我想这样做,只是动态地创建查询(查询本身根据某些输入数据而略有不同)。像这样:

String queryString = "<JPAQL part1>";
if (condition) queryString += "<JPAQL part2>";
queryString += "<JPAQL part3>";
Query query = entityManager.createQuery(queryString);
query.setParameter("foo", foo);
query.setParameter("bar", bar);
return query.getResultListAndApplySpringPaging(pageable);

不是想要将查询重写为Querydsl或Criteria API。部分原因是我不想花时间,部分原因是我的JPAQL包含一些Oracle特定的内容,这些内容可能很难表达(即使不是不可能)(例如ORDER BY NLSSORT(t.displayValue, 'NLS_SORT = XCZECH') ASC之类)。 / p>

是否可以通过Spring的分页机制手动传递Stringjavax.persistence.Query

2 个答案:

答案 0 :(得分:0)

如果创建2个方法怎么办:一个带有part2的方法,一个没有part2的方法,然后根据条件调用适当的方法。

@Query("<part part3>")
Page<Person> findBySomething(String foo, String bar, Pageable pageable);

@Query("<part1 part2 part3>")
Page<Person> findBySomethingElse(String foo, String bar, Pageable pageable);

...

return condition?findBySomethingElse(foo, bar, pageable):findBySomething(foo, bar, pageable);

答案 1 :(得分:0)

因此,在调试Spring内部构件一段时间后,我得到了类似于解决方案的东西。它跳过了Spring所做的许多事情(这意味着它不那么普遍),但至少在简单的情况下,它似乎对我有用。

String queryString = dynamicallyComposeQueryForConditions(someConditions);
String countQueryString = QueryUtils.createCountQueryFor(queryString);
Query query = entityManager.createQuery(queryString);
Query countQuery = entityManager.createQuery(countQueryString);
query.setParameter("foo", foo);
query.setParameter("bar", bar);
countQuery.setParameter("foo", foo);
countQuery.setParameter("bar", bar);
query.setFirstResult((int) pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
return PageableExecutionUtils.getPage(query.getResultList(), pageable,
        () -> (long) countQuery.getSingleResult());

显然,还有改进的空间。首先,两个查询都需要具有相同的参数集,出于简单起见,不应该像我在此处那样进行设置。第二,getPage非常聪明,仅在需要时才执行countQuery(或更确切地说totalSupplier)(并非总是如此)。这意味着即使调用QueryUtils.createCountQueryFor(queryString)然后再调用entityManager.createQuery(countQueryString)也不总是必须的,实际上应该只在totalSupplier内部进行。