You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Spring Data Sort动态排序自定义JPQL返回的嵌套实体?

问题描述

我在Spring Data Repository中定义了如下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

但返回结果未排序。开启org.springframework.web的trace日志后,发现我的请求中Sort被解析为UNSORTED,而相同依赖版本、代码及配置的其他项目中,Sort能被正常解析为model.name: DESC。

域模型如下:

@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;
}

问题分析

核心原因是Spring Data REST默认基于Repository管理的**主实体(Car)**校验并解析sort参数,但你的请求中sort=model.name是针对关联实体Model的属性,不属于Car的直接属性,导致参数解析校验失败,最终Sort被置为UNSORTED。

解决方案

方案1:在JPQL中通过SpEL直接引用Sort参数

修改Repository的JPQL查询,使用Spring Data的SpEL表达式?#{#sort}将传入的Sort参数直接转换为JPQL的order by子句:

public interface CarRepository extends Repository<Car, Integer> {
    
    @Query("select distinct c.model from Car c where c.id in :ids order by ?#{#sort}")
    Set<Model> findDistinctModelByIdIn(@Param("ids") Set<Integer> ids, Sort sort);
}

此时客户端请求需调整sort参数为Model的直接属性,无需加model.前缀:

http://localhost:8080/api/cars/search/findDistinctModelByIdIn?ids=1,33,55,43&sort=name,desc

方案2:自定义Sort参数解析器

如果需要保留客户端请求的model.name前缀,可自定义参数解析逻辑去掉前缀:

  1. 实现自定义Sort解析器:
@Component
public class CustomSortResolver extends SortHandlerMethodArgumentResolver {

    @Override
    protected Sort parseParameterIntoSort(String[] source, SortDefaults defaults) {
        String[] adjustedSource = Arrays.stream(source)
                .map(s -> s.replace("model.", ""))
                .toArray(String[]::new);
        return super.parseParameterIntoSort(adjustedSource, defaults);
    }
}
  1. 配置Spring Data REST使用自定义解析器:
@Configuration
public class RestConfig implements RepositoryRestConfigurer {

    @Autowired
    private CustomSortResolver customSortResolver;

    @Override
    public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
        configurer.addCustomResolver(customSortResolver);
    }
}

配置完成后,客户端原请求sort=model.name,desc即可正常生效。

方案3:使用Projection定义返回结构

定义Model的Projection,让Spring Data REST识别返回类型的属性,从而正常解析sort参数:

public interface ModelProjection {
    String getName();
    // 按需添加其他属性
}

修改Repository方法的返回类型:

@Query("select distinct c.model from Car c where c.id in :ids")
Set<ModelProjection> findDistinctModelByIdIn(@Param("ids") Set<Integer> ids, Sort sort);

客户端请求使用sort=name,desc即可实现排序。

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 07:45:34