我有一个我要订购的表格列。问题是列值包含数字和文本。例如,结果现在按此顺序排序。
1. group one
10. group ten
11. group eleven
2. group two
但是我希望自然地订购结果,比如
1. group one
2. group two
10. group ten
11. group eleven
在查看Spring配置时,我似乎无法找到允许您执行此操作的选项。我使用Spring Pageable类设置我的订单字段和方向,另外使用JPA规范。该方法本身返回一个默认为前20个结果的页面。
我不相信Oracle支持开箱即用的自然订购,所以我有一个存储过程。使用此过程运行查询,我得到了所需的结果。
select ... from group order by NATURALSORT(group.name) asc
正如您所料,我希望通过将其包装在包含文本的每个有序列周围来使用该过程。同时保持使用可分页/页面和规范。我在这方面所做的研究指出了一个可能包括
的解决方案但我似乎没有找到允许我使用本机SQL设置顺序的方法。我找到设置顺序的唯一方法是调用orderBy
并包含Order
对象。
一般而言。
order by column
方法的同时使用我的存储过程包装单个Page findAll(Pageable, Specifications)
?提前致谢。
答案 0 :(得分:2)
在深入研究Spring JPA和Hibernate的源代码之后,我设法找到了解决问题的方法。我很确定这不是解决它的好方法,但它是我唯一能找到的方法。
我最终通过扩展SingularAttributePath
类为查询的“order by”部分实现了一个包装器。此类有一个render方法,用于生成插入实际查询的字符串。我的实现看起来像这样
@Override
public String render(RenderingContext renderingContext) {
String render = super.render(renderingContext);
render = "MYPACKAGE.NSORT(" + render + ")";
return render;
}
接下来,我扩展了SimpleJpaRepository类中的Order转换功能。默认情况下,这是通过调用QueryUtils.toOrders(sort, root, builder)
来完成的。但由于调用它的方法无法覆盖,我最终自己调用了toOrder
方法,并根据自己的喜好改变了结果。
这意味着通过SingularAttributePath
类的自定义实现替换结果中的所有订单。作为额外的我扩展了Sort
类,Pageable
类使用它来控制包裹的内容和不包含的内容(称为NaturalOrder)。但我会在一秒钟内完成。我的实现看起来很接近(遗漏了一些检查)
// Call the original method to convert the orders
List<Order> orders = QueryUtils.toOrders(sort, root, builder);
for (Order order : orders) {
// Fetch the original order object from the sort for comparing
SingularAttributePath orderExpression = (SingularAttributePath) order.getExpression();
Sort.Order originalOrder = sort.getOrderFor(orderExpression.getAttribute().getName());
// Check if the original order object is instantiated from my custom order class
// Also check if the the order should be natural
if (originalOrder instanceof NaturalSort.NaturalOrderm && ((NaturalSort.NaturalOrder) originalOrder).isNatural()){
// replace the order with the custom class
Order newOrder = new OrderImpl(new NaturalSingularAttributePathImpl(builder, expression.getJavaType(), expression.getPathSource(), expression.getAttribute()));
resultList.add(newOrder);
}else{
resultList.add(order);
}
}
return resultList;
然后通过调用query.orderBy(resultlist)
将返回列表添加到查询中。那就是后端。
为了控制换行条件,我还扩展了Sort
使用的Pageable
类(提到这几行)。我想要添加的唯一功能是在方向枚举中有4种类型。
最后两个值仅用作占位符。它们设置了isNatural
布尔值(扩展Order
类的变量),它在条件中使用。在将它们转换为查询时,它们将映射回其默认变体。
public Direction getNativeDirection() {
if (this == NaturalDirection.NASC)
return Direction.ASC;
if (this == NaturalDirection.NDESC)
return Direction.DESC;
return Direction.fromString(String.valueOf(this));
}
最后,我替换了SortHandlerMethodArgumentResolver
使用的PageableHandlerMethodArgumentResolver
。这样做的唯一方法是创建我的NaturalSort
类的实例并将它们传递给Pageable对象,而不是默认的Sort
类。
最后,我能够调用相同的REST端点,而结果的排序方式不同。
Default Sorting
/api/v1/items?page=0&size=20&sort=name,asc
Natural Sorting
/api/v1/items?page=0&size=20&sort=name,nasc
我希望这个解决方案可以帮助那些在自然排序和弹簧JPA方面有相同或衍生问题的人。如果您有任何疑问或改进,请告诉我。
答案 1 :(得分:1)
我不知道有任何这样的功能。然而,您可以将数字存储在单独的列中,然后按该列排序,这样可以提供更好的排序性能作为额外的好处。