调用getLocation方法时出现ID类型不匹配错误排查求助
解决JPA复合主键类型不匹配的问题
嘿,这个问题我之前处理过,一眼就能看出是复合主键的使用姿势不对!咱们来理清楚问题出在哪,怎么解决:
问题根源
你的实体类用了三个@Id字段定义复合主键(emi、latitude、longitude),但没有告诉JPA如何封装这些主键字段。当你调用getLocation方法时,大概率是传入了单个Integer类型的参数,而JPA无法识别这种零散的主键参数,就会抛出“Provided id of the wrong type”的错误——它期待的是能承载所有主键字段的类,结果你给了个单独的Integer。
解决步骤
1. 创建专门的主键类
JPA要求复合主键必须用一个实现Serializable的类来封装,我们先写这个主键类(比如叫LocationId):
import java.io.Serializable; import java.util.Objects; public class LocationId implements Serializable { // 和实体类主键字段一一对应 private String emi; private Double latitude; private Double longitude; // 必须有无参构造器(JPA反射实例化用) public LocationId() {} // 全参构造器方便快速创建主键对象 public LocationId(String emi, Double latitude, Double longitude) { this.emi = emi; this.latitude = latitude; this.longitude = longitude; } // 重写equals和hashCode是JPA的硬性要求,用来判断主键是否唯一 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; LocationId that = (LocationId) o; return Objects.equals(emi, that.emi) && Objects.equals(latitude, that.latitude) && Objects.equals(longitude, that.longitude); } @Override public int hashCode() { return Objects.hash(emi, latitude, longitude); } // 补全三个字段的getter和setter方法 public String getEmi() { return emi; } public void setEmi(String emi) { this.emi = emi; } public Double getLatitude() { return latitude; } public void setLatitude(Double latitude) { this.latitude = latitude; } public Double getLongitude() { return longitude; } public void setLongitude(Double longitude) { this.longitude = longitude; } }
2. 修改实体类的主键配置
给你的实体类加上@IdClass注解,指定刚才写的主键类,同时保留原来的三个@Id字段:
@Entity @IdClass(LocationId.class) // 关键:告诉JPA用这个类作为主键的载体 public class Location { @Id @Column(name = "emi") private String emi; @Id @Column(name = "latitude") private Double latitude; @Id @Column(name = "longitude") private Double longitude; // 你的其他字段和方法... // 补全getter和setter public String getEmi() { return emi; } public void setEmi(String emi) { this.emi = emi; } public Double getLatitude() { return latitude; } public void setLatitude(Double latitude) { this.latitude = latitude; } public Double getLongitude() { return longitude; } public void setLongitude(Double longitude) { this.longitude = longitude; } }
3. 正确调用getLocation方法
现在不能再传单个Integer了,要传入LocationId对象来匹配复合主键:
// 创建主键对象 LocationId locationId = new LocationId("your-emi-value", 31.2304, 121.4737); // 调用查询方法 Location location = entityManager.find(Location.class, locationId);
额外说明
如果你更喜欢用@EmbeddedId的方式,也是可以的:只需要给LocationId类加上@Embeddable注解,然后在实体类里用@EmbeddedId代替三个@Id字段,效果是一样的,选哪种看你的习惯就行。
内容的提问来源于stack exchange,提问作者kitiya
相关产品推荐
相关产品推荐

