【问题标题】:JPA Pageable Sort order case sensitiveJPA 可分页排序顺序区分大小写
【发布时间】:2018-11-09 13:52:39
【问题描述】:

我正在使用 JpaRepository Pageable 查询进行分页。除了排序字段区分大小写的问题外,所有事情都运行良好。以下查询用于获取列表。

Pageable pageable = null;
if (paginationRequestDTO.getSortOrder().equalsIgnoreCase("desc"))
    pageable = new PageRequest(page, size, Sort.Direction.DESC, sortfiled);
else
    pageable = new PageRequest(page, size, Sort.Direction.ASC, sortfiled);

Page<Audi> audiPage = null;
audiencePage = audiRepository.search(paginationRequestDTO.getSearchKey(), pageable);

奥迪表值为:apple,az,Ajay,Bala。 当我使用 asc 的排序顺序和排序字段名称进行搜索时, 原始输出:Ajay,Bala,apple,az。 预期输出:Ajay,apple,az,Bala

我正在使用 mysql 数据库。表引擎 - Innodb,characterst-utf8,collate-utf8_bin.

请注意,它不是重复的问题。我没有得到这个问题的确切答案。提前致谢。

【问题讨论】:

标签: java spring-data-jpa


【解决方案1】:

已编辑:正如harsh 正确指出的那样,这需要在数据库级别使用正确的排序规则来解决。这很重要,因为您可能希望在排序列上有一个索引以获得最佳性能。

但还有其他用例可以将过滤与排序结合在一起,而不是纯列值,例如根据描述的长度、列的总和或平均值等。因此,我包括一个 JPA 解决方案:

我最近为此苦苦挣扎,恐怕 Pageable 接口不支持开箱即用。

解决方案是使用EntityManagerCriteriaBuilderCriteriaQuerySpecification 并手动实现分页。您可以找到解决方案here

需要手动构造Page对象:

public Page<Audi> getPage(int pageNumber, int pageSize, String descriptionFilter, Sorting sorting) {
    return new PageImpl<>(
            getPageItems(pageNumber, pageSize, descriptionFilter, sorting),
            PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.ASC, sorting.name())),
            getTotalCount(descriptionFilter)
    );
}

getPageItems 使用LIMITOFFSET 选择页面

private List<Audi> getPageItems(int pageNumber, int pageSize, String descriptionFilter, Sorting sorting) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Audi> query = cb.createQuery(Audi.class);
    Root<Audi> root = query.from(Audi.class);
    query.where(createSpecification(descriptionFilter).toPredicate(root, query, cb));

    if (sorting.equals(Sorting.descriptionCaseInsensitive)) {
        query.orderBy(cb.asc(cb.lower(root.get("description"))));
    } else {
        throw new UnsupportedOperationException("Unsupported sorting: " + sorting.name());
    }
    query.select(root);

    return em.createQuery(query)
            .setFirstResult(pageNumber * pageSize)
            .setMaxResults(pageSize)
            .getResultList();
}

getTotalCount 选择count(distinct(*))

private long getTotalCount(String descriptionFilter) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Long> query = cb.createQuery(Long.class);
    Root<Audi> root = query.from(Audi.class);
    query.where(createSpecification(descriptionFilter).toPredicate(root, query, cb));
    query.select(cb.countDistinct(root));

    // getSingleResult can return null, if no rows fulfill the predicate
    return Optional.ofNullable(em.createQuery(query).getSingleResult()).orElse(0L);
}

两者都重用相同的谓词,过滤行:

private Specification<Audi> createSpecification(String descriptionFilter) {
    return Specification.where(
            (root, query, criteriaBuilder) ->
                    criteriaBuilder.like(criteriaBuilder.lower(root.get("description")), "%" + descriptionFilter.toLowerCase() + "%")
    );
}

【讨论】:

  • 此问题与Pageable无关,与所使用的排序规则类型有关
  • 我明白你的意思。我完全忘记了整理。我的解决方案可以工作,但是它不能使用任何索引,因为生成的 SQL 将包含 ORDER by LOWER(column)。
  • 感谢您的重播。我必须只使用可分页而不是 EntityManager、CriteriaBuilder、CriteriaQuery、规范。所以也更改了排序规则,仍然无法正常工作。
猜你喜欢
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 2011-08-14
  • 2019-01-31
  • 2020-09-13
  • 2012-06-22
  • 1970-01-01
  • 2012-08-16
相关资源
最近更新 更多