Spring Data JPA如何实现按实体属性排序不硬编码字段名?
解决方案
方案1:使用Spring Data提供的TypedSort(推荐,无需额外依赖配置)
Spring Data 2.2及以上版本提供了类型安全的排序构造方式,直接通过实体类的Getter方法引用实现编译期字段校验:
// 构造类型安全的Sort对象 Sort sort = Sort.sort(Some.class) .by(Some::getFoo) // 直接用方法引用,字段改名后编译直接报错 .descending(); Pageable pageable = PageRequest.of(page, limit, sort);
如果需要根据请求参数动态切换排序字段,只需要维护一个请求参数到Getter方法的映射即可,完全避免硬编码字符串:
// 提前维护排序字段映射,Key为前端传的排序参数值 Map<String, Function<Sort.TypedSort<Some>, Sort.Order>> sortMapping = Map.of( "foo", typedSort -> typedSort.by(Some::getFoo).descending(), "bar", typedSort -> typedSort.by(Some::getBar).ascending() ); // 根据请求参数获取对应的排序规则 Sort.Order order = sortMapping.get(requestSortParam); Sort sort = order == null ? Sort.unsorted() : Sort.by(order);
方案2:使用JPA静态元模型
如果你的Spring Data版本较低不支持TypedSort,可以用JPA规范的静态元模型实现编译期校验:
- 首先引入JPA静态元模型生成依赖,以Hibernate实现为例,Maven添加如下依赖:
<dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-jpamodelgen</artifactId> <version>对应你的Hibernate版本</version> <scope>provided</scope> </dependency>
- 编译项目后会自动生成元模型类
Some_,包含实体类所有字段的静态常量:
// 自动生成的元模型类示例 @Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor") @StaticMetamodel(Some.class) public abstract class Some_ { public static volatile SingularAttribute<Some, Foo> foo; public static volatile SingularAttribute<Some, Bar> bar; public static final String FOO = "foo"; public static final String BAR = "bar"; }
- 构造Sort时直接引用元模型的常量即可,字段修改后元模型会同步更新,编译期就能发现不匹配的问题:
Sort sort = Sort.by(Sort.Direction.DESC, Some_.FOO); Pageable pageable = PageRequest.of(page, limit, sort);
两种方案都完全避免了硬编码写字段名字符串,不需要额外编写JPQL,排序逻辑完全复用Spring Data JPA的原有能力,字段修改后只要没同步修改排序代码,编译阶段就会报错,完全解决运行时才出问题的隐患。
内容的提问来源于stack exchange,提问作者Ilia
相关产品推荐
相关产品推荐

