如何接受 JPA 排序值的 @OrderBy 作为动态参数?

Posted

技术标签:

【中文标题】如何接受 JPA 排序值的 @OrderBy 作为动态参数?【英文标题】:How to accept @OrderBy of JPA sort value as a dynamic parameter? 【发布时间】:2020-07-22 02:17:30 【问题描述】:

我想根据查询参数 sort 对嵌套集合属性进行动态排序。

假设我有一个实体 A

class A

@OneToMany(mappedBy="a")
private Set<B> bset;



class B

private LocalDate datefield;
@ManyToOne
private C c;



class C

private Double quantity;


我用 findAll(Specification specification,Pageable page) 调用 A 的存储库

在 UI 中,rest 控制器使用如下模式调用排序参数

 url?page=0&size=10&sort=bset_datefield

因为它是一个嵌套集合,所以上面的排序不起作用。 可排序的字段是日期字段、数量。

我知道 @OrderBy("bset.datefield") 会起作用,但参数应该是动态的。

调用 find All on A repository 时如何实现这一点?

【问题讨论】:

Set 的元素没有顺序。您将需要改用 SortedSet。要根据需要进行动态排序,我认为您需要创建自定义 SQL 查询或在从数据库加载元素后对其进行排序。 【参考方案1】:

无法完成,因为初始化 entityManager 时会评估注释。

最好的选择是,创建一个有序的查询,或者如果从现在开始使用 Java 8,则在获得列表后,使用流的排序方法进行排序。

【讨论】:

【参考方案2】:

你不能这样做,只使用 Spring Data 是不可能的。

从概念上讲,您使用的是在 A 类上参数化的 JpaSpecificationExecutorSpecifications。

在指定的findAll 方法中,您可以按任何属性对A 进行排序,甚至按嵌套属性,但您正在对A 进行排序。

您可以指示 JPA 提供程序 fetch 一个集合,按集合字段排序,但您不能对集合本身进行排序。

即使在ASpecification 正文中,您使用某种涉及必须排序的集合的子查询,并且您在此子查询中通过集合的字段建立排序,我认为- 也许应该测试 - JPA 提供者将返回类 A 的实例,然后根据提供的 @OrderBycriteria 初始化集合。

顺便说一句,在语义上,使用@OrderBy 时使用List 而不是Set 始终是一个好习惯。

因此,如果您想对集合进行排序,我认为您唯一的选择是处理在查询字符串中接收到的排序条件,并在将数据返回给客户端之前通过对象比较在内存中对集合进行排序。

【讨论】:

【参考方案3】:

跟随本教程:REST Query Language with Spring Data JPA and Querydsl

当你使用

MyUserPredicatesBuilder

它会变魔术。

@Controller
public class UserController 

@Autowired
private MyUserRepository myUserRepository;

@RequestMapping(method = RequestMethod.GET, value = "/myusers")
@ResponseBody
public Iterable<MyUser> search(@RequestParam(value = "search") String search) 
    MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder();

    if (search != null) 
        Pattern pattern = Pattern.compile("(\w+?)(:|<|>)(\w+?),");
        Matcher matcher = pattern.matcher(search + ",");
        while (matcher.find()) 
            builder.with(matcher.group(1), matcher.group(2), matcher.group(3));
        
    
    BooleanExpression exp = builder.build();
    return myUserRepository.findAll(exp);

【讨论】:

以上是关于如何接受 JPA 排序值的 @OrderBy 作为动态参数?的主要内容,如果未能解决你的问题,请参考以下文章

具有空值的 Linq.JS OrderBy

JPA Criteria Query API 和两列排序

如何在 jpa spring 存储库中使用 OrderBy?

如何编写基于作为父实体spring数据jpa的一部分的字段对结果进行排序的查询方法

JPA + MariaDB:排序规则如何影响 unicode 支持?

使用 JPA 按嵌套属性排序时结合 DISTINCT 和 ORDER BY