Spring JPA实体关联查询出现String转Long转换失败问题求助
解决Spring JPA中通过国家编码查询州的类型转换错误
我之前碰到过类似的问题,咱们先拆解下问题根源:你用@RepositoryRestResource时,Spring Data REST的默认路径匹配规则把findByCountryCode当成了State实体的ID(Long类型)来解析,所以才会抛出字符串转Long的异常。下面是具体的修复步骤和优化建议:
问题重现
你实现了Country和State的关联实体,然后在StateRepository中定义了自定义查询方法,但测试时访问http://localhost:8080/api/states/findByCountryCode?code=BR时触发错误:
Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'findByCountryCode'; nested exception is java.lang.NumberFormatException: For input string: "findByCountryCode"
你的实体和Repository代码如下:
Country实体
@Entity @Table(name="COUNTRY",catalog ="SPRINGANGULAR") @Data @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(of = {"id","code","countryName"}, exclude = "states") public class Country { @Id @SequenceGenerator(name="COUNTRY_SEQ", sequenceName="COUNTRY_SEQ", allocationSize=1) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="COUNTRY_SEQ") @Column(name="ID", nullable = false) private long id; @Column(name="CODE") private String code; @Column(name="COUNTRY_NAME") private String countryName; @OneToMany(fetch=FetchType.LAZY,mappedBy="country", cascade= CascadeType.ALL) private Set<State> states = new HashSet<State>(); public Country(String code, String countryName) { super(); this.code = code; this.countryName = countryName; } }
State实体
@Entity @Table(name="STATE",catalog ="SPRINGANGULAR") @Data @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(of = {"id", "stateName"}) public class State { @Id @SequenceGenerator(name="STATE_SEQ", sequenceName="STATE_SEQ", allocationSize=1) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="STATE_SEQ") @Column(name="ID", nullable = false) private long id; @Column(name="STATE_NAME") private String stateName; @ManyToOne(fetch=FetchType.LAZY,cascade= CascadeType.ALL) @JoinColumn(name = "COUNTRY_ID", nullable = false) private Country country; public State(String stateName, Country country) { super(); this.stateName = stateName; this.country = country; } }
问题出在StateRepository
@CrossOrigin("http://localhost:4200") @RepositoryRestResource(collectionResourceRel = "states", path = "states") public interface StateRepository extends JpaRepository<State, Long>{ @Query("SELECT s FROM State s \n" + "LEFT JOIN Country c ON c.id = c.id \n" + "WHERE c.code = :code \n" + "ORDER BY s.id ASC") List<State> findByCountryCode(@RequestParam("code") String code); }
具体修复步骤
1. 给自定义查询方法添加@RestResource注解
Spring Data REST不会自动识别自定义查询方法作为端点,你需要用@RestResource明确指定它的路径。同时还要修正JPQL的错误关联语句:
@CrossOrigin("http://localhost:4200") @RepositoryRestResource(collectionResourceRel = "states", path = "states") public interface StateRepository extends JpaRepository<State, Long>{ // 用@RestResource指定查询端点的路径和关系名 @RestResource(path = "by-country-code", rel = "by-country-code") // 修正JPQL:直接通过实体关联字段查询,不需要手动写ON条件 @Query("SELECT s FROM State s JOIN s.country c WHERE c.code = :code ORDER BY s.id ASC") // 用@Param映射JPQL中的参数,而不是@RequestParam List<State> findByCountryCode(@Param("code") String code); }
2. 使用正确的请求路径
Spring Data REST的自定义查询默认挂载在/search路径下,所以你需要用这个URL测试:
http://localhost:8080/api/states/search/by-country-code?code=BR
3. 额外的优化建议
- 修正State实体的级联策略:你给
@ManyToOne设置了CascadeType.ALL,这意味着删除State时会级联删除对应的Country,这通常不符合业务逻辑,建议改成CascadeType.PERSIST(仅保存时级联)或者移除该属性(根据实际需求调整)。 - JPQL查询优化:原来的
LEFT JOIN Country c ON c.id = c.id是无效的关联条件,直接使用s.country即可让JPA自动处理表关联,既简洁又不易出错。
内容的提问来源于stack exchange,提问作者Sercan Noyan Germiyanoğlu
相关产品推荐
相关产品推荐

