英文:
How to accept @OrderBy of JPA sort value as a dynamic parameter?
问题
我想动态排序一个嵌套的集合属性,基于查询参数 "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;
}
我正在调用 A 的仓库方法:findAll(Specification specification, Pageable page)
。
从用户界面(UI)调用 REST 控制器时,使用以下模式的排序参数:
url?page=0&size=10&sort=bset_datefield
由于这是一个嵌套集合,上述排序不起作用。可排序的字段是 datefield
和 quantity
。
我知道 @OrderBy("bset.datefield") 可以工作,但参数应该是动态的。
在调用 A 仓库上的 findAll 方法时,我该如何实现这一点?
英文:
I want to sort a nested collection property dynamically based on the query parameter sort.
Suppose i have an entity A as
class A{
@OneToMany(mappedBy="a")
private Set<B> bset;
}
class B{
private LocalDate datefield;
@ManyToOne
private C c;
}
class C
{
private Double quantity;
}
I am calling repository of A with findAll(Specification specification,Pageable page)
From UI, rest controller is called with sort param as below pattern
url?page=0&size=10&sort=bset_datefield
As it is a nested collection,the above sort is not working.
The sortable fields are datefield,quantity.
I know @OrderBy("bset.datefield") will work,but the parameter should be dynamic.
How can i achieve this when invoking find All on A repository ?
答案1
得分: 0
无法完成,因为在初始化entityManager时,会评估注释。
最佳选项是创建一个已排序的查询,或者一旦获取了列表,如果您从现在开始使用Java 8,可以使用流的sort方法进行排序。
英文:
It cannot be done because when the entityManager is initialized the annotations are evaluated.
The best options are, create a query that comes ordered or once the list is obtained if you use Java 8 from now on, order with the sort method of stream.
答案2
得分: 0
你不能这样做,仅使用Spring Data是不可能的。
在概念上,您正在使用JpaSpecificationExecutor
和基于类A参数化的Specification
。
在指定的findAll
方法中,您可以按任何属性对A
进行排序,甚至可以按嵌套属性进行排序,但您正在对A
进行排序。
您可以指示JPA提供程序fetch
一个集合,按集合字段排序,但不能对集合本身进行排序。
即使在A
的Specification
体中使用某种涉及必须排序的集合的子查询,并在这个子查询中按集合字段排序,我认为 - 也许应该测试一下 - JPA提供程序将返回类A
的实例,然后根据提供的@OrderBy
标准初始化集合。
顺便说一句,在语义上,使用@OrderBy
时,始终最好使用List
而不是Set
。
所以如果您想对集合进行排序,我认为您唯一的选择是在查询字符串中处理接收到的排序标准,并在将数据返回给客户端之前通过对象比较在内存中对集合进行排序。
英文:
You cannot do that, it is not possible using only Spring Data.
Conceptually, you are using a JpaSpecificationExecutor
and Specification
s parameterized in terms on the class A.
In the indicated findAll
method you can sort A
by any property, even by a nested one, but you are sorting A
.
You can instruct the JPA provider to fetch
a collection, to sort by a collection field, but you cannot sort the collection itself.
Even in the case that in the Specification
body of A
you use some kind of subquery which involve the collection that must be sorted, and you establish a sort by the fields of the collection in this subquery, I think - maybe it should be tested - that the JPA provider will return the instances of class A
and then initialize the collection according to the provided @OrderBy
criteria.
By the way, and semantically, it is always a good practice to use a List
instead of a Set
when using @OrderBy
.
So if you want to sort the collection I think the only alternative you have is to process the sort criteria received in the query string and sort the collection in memory by object comparison before returning the data to the client.
答案3
得分: 0
以下是翻译好的部分:
"Following this tutorial: REST Query Language with Spring Data JPA and Querydsl
When you use
> MyUserPredicatesBuilder
It does the magic trick.
@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);
}
}
英文:
Following this tutorial: REST Query Language with Spring Data JPA and Querydsl
When you use
> MyUserPredicatesBuilder
It does the magic trick.
@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);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论