繁体   English   中英

是否可以使用 Spring 数据 Jpa 规范实现长度(属性)并按后者排序

[英]Is it possible to implement a length(attribute) and sort by the latter with Spring Data Jpa Specification

我正在更新谓词,基本上我想使用标准 API 转换以下查询。

select t, length(name) lens
from train t
left join line l on l.id = t.lineId 
    where l.code = '14'
order by lens, name

样本结果:

其他栏目 姓名 镜片
... AA-2 4
... AA-3 4
... AA-7 4
... AA-9 4
... AA-10 5
... AA-17 5
... BB-1 9
... BB-3 9
... BB-20 9

这就是我做的这么快:

1- 在服务中 class

public Page<Train> getTrains(Pageable pageable, FilterRequest filterRequest) {
   if (filterRequest == null || CollectionUtils.isEmpty(filterRequest.getTrainsFilters())) {
        return trainRepository.findAll(pageable);
   }
   TrainSpecification trainSpecification = new TrainSpecification(filterRequest);
   // add a field lens in train => length(name) and add it to sortField in pageable
   // sortFields = [lens, name]
   Page<Train> trains = trainRepository.findAll(trainSpecification, pageable);
   return trains;
}

2- 在规格 class

@AllArgsConstructor
@Data
public class TrainSpecification implements Specification<Train> {
    private transient FilterRequest filterRequest;
    private static final String CODE = "code";

    @Override
    public Predicate toPredicate(Root<Train> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        Predicate[] predicatesLinesTrains = getTrainsLinesPredicates(root, criteriaBuilder);
        return criteriaBuilder.and(predicatesLinesTrains);
    }

    private Predicate[] getTrainsLinesPredicates(Root<Train> root, CriteriaBuilder criteriaBuilder) {
        // I think that update should be done on the root here but couldn't figure out how
        final Join<Train, Line> trainLineJoin = root.join("line", JoinType.LEFT);
        Predicate[] predicatesLine = new Predicate[0];
        if (!CollectionUtils.isEmpty(this.filterRequest.getTrainsFilters())) {
            predicatesLine = this.filterRequest.getTrainsFilters()
                .stream()
                .filter(filterCriteria -> filterCriteria.getValue() != null)
                .map(filterCriteria ->
                    {
                        switch (filterCriteria.getMatchMode().toUpperCase(Locale.ROOT)) {
                            case "IN":
                                return criteriaBuilder.in(root.get(filterCriteria.getName()))
                                    .value(filterCriteria.getValue());
                            case "EQUAL":
                                return criteriaBuilder.equal(trainLineJoin.get(CODE), filterCriteria.getValue());
                            default:
                                throw new OperationNotSupportedException(filterCriteria.getMatchMode());
                        }
                    }
                ).toArray(Predicate[]::new);
        }
        return predicatesLine;
    }
}

3- FilterRequest class

@Data
@AllArgsConstructor
@NoArgsConstructor
public class FilterRequest {
    private List<FilterCriteria> activitiesFilters;
    private List<FilterCriteria> trainsFilters;
    private String sortField;
    private String sortOrder;

}

4- 过滤器标准 class

@Data
@NoArgsConstructor
@AllArgsConstructor
public final class FilterCriteria {
    @NotBlank
    private String name;

    private Object value;

    private String matchMode;
}

根据 SQL 要求,我必须在火车中创建一个字段。 查询数据库时应更新此字段。 然后我可以将该字段添加为可分页的可排序参数。 我暂时不知道该怎么做。

想法

  1. 我创建了一个视图(train_name_view)并将其与标准 API 一起使用
  2. 我在火车上创建了一个场镜并用它来分类。
  3. 我寻找更优雅的方式来更新标准 API 来完成它

关于哪种方法最好的任何想法。

我终于通过使用 Criteria API 解决了这个问题。

我用代码更新了toPredicate我的规范

public Predicate toPredicate(Root<Train> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
    customSortByName(root, query, criteriaBuilder);
    Predicate[] predicatesLinesTrains = getTrainsLinesPredicates(root, criteriaBuilder);
    return criteriaBuilder.and(predicatesLinesTrains);
}
private void customSortByName(Root<Train> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        if (this.filterRequest.getSortOrder().equalsIgnoreCase(ASC)) {
            query.orderBy(criteriaBuilder.asc(criteriaBuilder.length(root.get(this.filterRequest.getSortField()))),
                criteriaBuilder.asc(root.get(this.filterRequest.getSortField())));
        } else if (this.filterRequest.getSortOrder().equalsIgnoreCase(DESC)){
            query.orderBy(criteriaBuilder.desc(criteriaBuilder.length(root.get(this.filterRequest.getSortField()))),
                criteriaBuilder.desc(root.get(this.filterRequest.getSortField())));
        }
}

customSortByName对应于 SQL 查询

SELECT name
FROM train 
order by length(name), name

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM