使用Lombok Builder插入复合主键Entity时ID类型错误的解决咨询
问题描述
使用Spring Boot 3.1.7,通过反向工程生成包含3个主键的实体类Apibs及对应复合主键类ApibsPK。使用Lombok Builder语法创建Apibs对象并执行保存操作时,抛出如下错误:
org.springframework.dao.InvalidDataAccessApiUsageException: Supplied id had wrong type: entity 'com.sageapservice.entity.mssql.Apibs' has id type 'class com.sageapservice.entity.mssql.ApibsPK' but supplied id was of type 'class java.lang.Integer'
尝试直接为实体字段赋值(报错),或创建ApibsPK对象作为ID传入,但Builder不接受未定义字段,程序无法运行。
现有代码
实体类Apibs
@Entity @AllArgsConstructor @Builder @NoArgsConstructor @IdClass(ApibsPK.class) public class Apibs { @Id @Column(name = "CNTBTCH", nullable = false, precision = 0) private int cntbtch; @Id @Column(name = "CNTITEM", nullable = false, precision = 0) private int cntitem; @Id @Column(name = "CNTPAYM", nullable = false, precision = 0) private int cntpaym; @Basic @Column(name = "AUDTDATE", nullable = false, precision = 0) private int audtdate; @Basic @Column(name = "AUDTTIME", nullable = false, precision = 0) private int audttime; @Basic @Column(name = "AUDTUSER", nullable = false, length = 8) private String audtuser; @Basic @Column(name = "AUDTORG", nullable = false, length = 6) private String audtorg; @Basic @Column(name = "DATEDUE", nullable = false, precision = 0) private int datedue; // ... }
复合主键类ApibsPK
@NoArgsConstructor @AllArgsConstructor @Builder public class ApibsPK implements Serializable { @Column(name = "CNTBTCH", nullable = false, precision = 0) @Id private int cntbtch; @Column(name = "CNTITEM", nullable = false, precision = 0) @Id private int cntitem; @Column(name = "CNTPAYM", nullable = false, precision = 0) @Id private int cntpaym; // ... }
解决方案
1. 修正复合主键类的注解冗余
ApibsPK作为@IdClass指定的主键类,不需要@Id和@Column注解(这些注解仅需在实体类的主键字段上标注)。同时必须重写equals和hashCode方法,确保JPA能正确识别主键:
import java.util.Objects; @NoArgsConstructor @AllArgsConstructor @Builder public class ApibsPK implements Serializable { private int cntbtch; private int cntitem; private int cntpaym; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ApibsPK apibsPK = (ApibsPK) o; return cntbtch == apibsPK.cntbtch && cntitem == apibsPK.cntitem && cntpaym == apibsPK.cntpaym; } @Override public int hashCode() { return Objects.hash(cntbtch, cntitem, cntpaym); } }
2. 正确使用实体类的Builder创建对象
在@IdClass模式下,实体类本身持有所有主键字段,无需单独传入ApibsPK对象。直接通过Builder设置三个主键字段即可:
Apibs apibs = Apibs.builder() .cntbtch(1) .cntitem(2) .cntpaym(3) .audtdate(20240520) .audttime(123456) .audtuser("ADMIN") .audtorg("ORG001") .datedue(20240620) .build(); // 执行保存操作 apibsRepository.save(apibs);
3. 排查保存操作的调用方式
确保调用save方法时传入的是完整的Apibs对象,而非单个主键字段值(比如误传Integer类型的单个主键),这是导致错误提示中“Supplied id had wrong type”的常见原因。
内容的提问来源于stack exchange,提问作者seritrk6186

