[英]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 要求,我必须在火车中创建一个字段。 查询数据库时应更新此字段。 然后我可以将该字段添加为可分页的可排序参数。 我暂时不知道该怎么做。
想法
关于哪种方法最好的任何想法。
我终于通过使用 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.