Spring JPA用@EmbeddedId创建仓库报错:找不到UserRef的'empty'属性
问题描述
我尝试通过@Embeddable和@EmbeddedId创建Repository,相关代码如下:
UserRef 实体类
public class UserRef { @EmbeddedId private UserRefId id; }
UserRefId 嵌入式ID类
public class UserRefId implements Serializable { @NotNull @Column(name = "USER_TYPE_CD") private String userTypeCd; @NotNull @Column(name = "USER_INTERNAL_CD") private String userInternalCd; }
但运行应用时抛出异常:
nested exception is java.lang.IllegalArgumentException : Failed to create query for method public abstract repository.UserRefRepository.findById(java.lang.String) ! No property 'empty' found for type 'UserRef'
我的Repository接口代码如下:
@Repository public interface UserRefRepository extends JpaRepository <UserRef, UserRefId> { public Map<String, Map<String, String>> findById (String refTypeCd); }
我尝试修改驼峰命名但完全无效,请问我哪里出错了?
问题原因及解决方法
核心问题
- 方法名冲突:
JpaRepository自带了findById(ID id)默认方法,参数类型是你指定的泛型ID(UserRefId),返回Optional<T>。你自定义的findById(String refTypeCd)和默认方法重名,但参数、返回类型都不匹配,导致Spring Data JPA解析方法名时逻辑混乱,触发错误。 - 返回类型不合法:直接让Repository返回
Map<String, Map<String, String>>不符合Spring Data JPA的方法返回规则,复杂集合类型会加剧解析错误。 - 嵌入式ID类缺失必要注解:
UserRefId没有添加@Embeddable注解,JPA无法识别它是可嵌入的ID类。
解决步骤
重命名自定义方法
改成和默认findById不冲突的名字,同时遵循嵌入式属性的路径命名规则(用id.属性名的结构):@Repository public interface UserRefRepository extends JpaRepository<UserRef, UserRefId> { // 对应UserRef.id.userTypeCd的属性路径 List<UserRef> findByIdUserTypeCd(String refTypeCd); }调整返回类型
Repository优先返回实体或实体集合,如需Map结构,在业务层将查询结果转换:// 业务层示例 public Map<String, Map<String, String>> convertToMap(List<UserRef> userRefs) { return userRefs.stream() .collect(Collectors.groupingBy( ref -> ref.getId().getUserTypeCd(), Collectors.toMap( ref -> ref.getId().getUserInternalCd(), ref -> // 这里映射你需要的值 ) )); }完善嵌入式ID类
添加@Embeddable注解,同时补充无参构造函数、equals和hashCode方法(JPA强制要求):@Embeddable public class UserRefId implements Serializable { @NotNull @Column(name = "USER_TYPE_CD") private String userTypeCd; @NotNull @Column(name = "USER_INTERNAL_CD") private String userInternalCd; // 无参构造函数 public UserRefId() {} // 带参构造函数(可选,方便使用) public UserRefId(String userTypeCd, String userInternalCd) { this.userTypeCd = userTypeCd; this.userInternalCd = userInternalCd; } // 重写equals和hashCode @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UserRefId userRefId = (UserRefId) o; return Objects.equals(userTypeCd, userRefId.userTypeCd) && Objects.equals(userInternalCd, userRefId.userInternalCd); } @Override public int hashCode() { return Objects.hash(userTypeCd, userInternalCd); } // getter、setter方法 public String getUserTypeCd() { return userTypeCd; } public void setUserTypeCd(String userTypeCd) { this.userTypeCd = userTypeCd; } public String getUserInternalCd() { return userInternalCd; } public void setUserInternalCd(String userInternalCd) { this.userInternalCd = userInternalCd; } }
内容的提问来源于stack exchange,提问作者DoGoodToEveryone
相关产品推荐
相关产品推荐

