Spring Boot JPA按嵌套字段排序时OrderBy失效问题求助
你的问题场景
你定义了一对多的JPA实体:
@Entity @Table(name = "past_price") public class PastPrice { @Id private String symbol; @OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL) @JoinColumn(name = "symbol") private Set<Price> prices = null; // getter和setter方法 } @Entity public class Price { @Id @Temporal(TemporalType.TIMESTAMP) private Date date; private String price; // getter和setter方法 }
然后尝试通过仓库方法名实现集合排序:
@Repository public interface PastPriceRepo extends JpaRepository<PastPrice,String> { PastPrice findBySymbol_OrderByPricesDate(String symbol); }
但调用后返回的prices集合完全无序,比如你给出的JSON结果里日期是乱序的:
{
"symbol": "SAX",
"prices": [
{"date": 1552295163000, "price": "234.00"},
{"date": 1552459623000, "price": "236.00"},
{"date": 1552470475000, "price": "232.00"},
{"date": 1553155398000, "price": "233.00"},
{"date": 1553762003000, "price": "234.00"},
{"date": 1552469784000, "price": "233.00"},
{"date": 1553755597000, "price": "235.00"},
{"date": 1553760225000, "price": "234.00"},
{"date": 1552284839000, "price": "226.00"}
]
}
问题出在哪?
你写的方法名findBySymbol_OrderByPricesDate不符合JPA的方法命名规则——JPA没办法通过这种方式直接对关联的子集合进行排序,方法名里的排序条件默认只能作用于主实体(也就是PastPrice)的字段,没法穿透到关联的Price实体上。
两种可行的解决办法
方法1:在实体关联上直接指定排序(推荐)
这是最省心的方式,直接在PastPrice的@OneToMany注解上加上@OrderBy,这样每次加载prices集合时都会自动按指定规则排序,不需要改仓库方法:
@Entity @Table(name = "past_price") public class PastPrice { @Id private String symbol; @OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL) @JoinColumn(name = "symbol") @OrderBy("date ASC") // 指定按Price的date字段升序排序 private Set<Price> prices = null; // getter和setter方法 }
之后仓库里只需要用最简单的查询方法就行:
PastPrice findBySymbol(String symbol);
小提示:因为Set集合本身的特性是无序的,部分JPA实现可能会影响排序效果,建议把Set<Price>改成List<Price>,这样排序后的结果会更稳定。
方法2:用JPQL手动编写带排序的查询
如果不想修改实体类,可以在仓库接口里写自定义的JPQL查询,通过JOIN FETCH关联子集合并排序:
@Repository public interface PastPriceRepo extends JpaRepository<PastPrice,String> { @Query("SELECT pp FROM PastPrice pp JOIN FETCH pp.prices p WHERE pp.symbol = :symbol ORDER BY p.date ASC") PastPrice findBySymbolWithSortedPrices(@Param("symbol") String symbol); }
这个查询会在加载PastPrice的同时,把关联的prices集合按date升序从数据库中查询出来,返回的集合自然就是有序的。
内容的提问来源于stack exchange,提问作者theanilpaudel

