You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:26:37