首页 > 解决方案 > JPA 可分页排序顺序区分大小写

问题描述

我正在使用 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.

请注意,它不是重复的问题。我没有得到这个问题的确切答案。在此先感谢。

标签: javaspring-data-jpa

解决方案


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

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

我最近为此苦苦挣扎,我担心 Pageable 接口不支持这个开箱即用。

解决方案是使用EntityManager, CriteriaBuilder,CriteriaQuerySpecification手动实现分页。您可以在此处找到解决方案。

您需要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)
    );
}

getPageItemsLIMIT使用和选择页面OFFSET

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() + "%")
    );
}

推荐阅读