我在Spring数据存储库中有以下JPQL查询:
public interface CarRepository extends Repository<Car, Integer> {
@Query("select distinct c.model from Car c where c.id in :ids")
Set<Model> findDistinctModelByIdIn(@Param("ids") Set<Integer> ids, Sort sort);
}
客户端按如下方式调用查询(通过Spring Data REST公开):
http://localhost:8080/api/cars/search/findDistinctModelByIdIn?ids=1,33,55,43&sort=model.name,desc
但是,返回的结果是未排序的。如何根据客户端排序请求参数进行排序?
Spring是否仅根据存储库管理的域类型进行排序(例如,只有Car
而不是Model
)?
更新
这是我的域模型:
@Entity
@Data
public class Car {
@Id
private Long id;
@ManyToOne
private Model model;
}
@Entity
@Data
public class Model {
@Id
private Long id;
private String name;
}
更新
打开org. springframe.web的跟踪后,我发现了以下内容:
2023-02-09T12:20:16.315-06:00 TRACE 21812---[io-9006-exec-10]o.s.web.method.Handler方法:参数:[org.springframework.data.rest.webmvc.RootResourceInformation@6e3e0c99,{ids=[33283,37901],sort=[model.name,desc]},findDiginctModelByIdIn,DefaultedPag可分页(可分页=Page request[number:0,size 20,sort:UNSORTED],isDefault=true),UNSORTED,org.springframework.data.rest.webmvc.PerstientEntityResourceAssembler…
但是,使用@Yuriy-Tsarkov项目时,会记录以下内容:
2023-02-09T12:16:17.818-06:00 TRACE 22460---[nio-8097-exec-1]o.s.web.method.Handler方法:参数:[org.springframework.data.rest.webmvc.RootResourceInformation@3e78567e,{ids=[33283,37901],sort=[model.name,desc]},findDiginctModelByIdIn,DefaultedPag可分页(可分页=Page request[number:0,size 20,sort:model.name:DESC],isDefault=false),model.name:DESC,org.springframework.data.rest.webmvc.PerstientEntityResourceAssembler…
因此,即使我使用完全相同版本的依赖项和我的代码,Spring也会感觉到一些差异
Spring是否仅根据存储库管理的域类型进行排序(例如,只有Car而不是Model)?
实际上,确实如此。我模拟了一个像你这样的案例,没有遇到任何问题。在这里。如果基石在Spring
的版本中呢?经常发生在某些版本中内部实现非常不同…
Spring当然支持这一点,唯一的事情是它执行交叉连接,这意味着您将从结果中丢失具有null Model的实体。
要对此进行调试,我建议您添加此配置:
spring:
jpa:
show-sql: true
然后,您可以在控制台/日志中检查执行的db查询并查看排序是否存在,从而找到问题是在查询生成中还是在数据中。
总结
Spring Data不会对具有自己的存储库并已导出(这是默认值)的嵌套实体进行排序。
细节
经过进一步研究,我找到了为什么@yuriy-tsarkov应用程序能够对嵌套实体进行排序而我的应用程序无法排序的答案。
问题原因
我有一个嵌套实体的存储库,Model
:
public interface ModelRepository extends Repository<Model, Integer> {
//various method defs
}
如果你在@yuriy-tsarkov应用程序中添加了Toy
,它将无法对他的PetRepository
返回的Toy
进行排序,就像我的应用程序无法对CarRepository
返回的Model
进行排序一样。
为什么?
因为一旦Model
(或Toy
在yuriy-tsarkovapp的情况下)有了自己的存储库,它就被认为是可链接的关联。即,org.springframework.data.rest. webmvc.map.Associations.isLinkableAssociation(持久属性
@Override
public boolean isMapped(PersistentProperty<?> property) {
return repositories.hasRepositoryFor(property.getActualType()) && super.isMapped(property);
}
这是因为repositories. hasRepositoryFor返回true b/c如上所述,我有一个Model
的存储库,并且super.isMap
也返回true。只有在定义了@RestResource(导出=false)
时,super.isMap
才返回false。因为我没有定义它,所以它返回true。
(我相信这可能是有意义的,因为我的Model
可能仅用链接表示。也就是说,我似乎仍然希望这些链接按模型名称排序。)
解决方案
在我的例子中,我需要一个管理Model
实体的存储库。因此,我不能简单地删除ModelRepository
。
但是,我可以允许不导出嵌套实体propmodel
:
@Entity
@Data
public class Car {
@Id
private Long id;
@ManyToOne
@RestResource(exported=false)
private Model model;
}
这允许super. isMap
返回false(因为它不是导出的资源)。然后排序确实有效,它不仅仅是可能返回的链接。
我觉得这个解决方案是一个变通方法,即使只提供了链接,Spring Data Rest仍然应该能够对属性进行排序。在我的场景中,repo无论如何都没有提供链接(即使没有@RestResource)。