jpa复合主键应用及常见报错问题

本文介绍复合主键的概念及其在Hibernate中的实现方式,并详细解释如何定义复合主键类和使用@IdClass注解。此外,还探讨了复合主键在依赖其他表主键时的配置方法,并列举了一些常见的错误案例及解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

复合主键即使用表中多个字段做为主键Id,正常情况下一般一张表只有一个字段作为主键Id,而有时我们需要关联多张表或单个主键Id在业务中无法区分时使用复合主键可以比较容易解决这些问题。

Hibernate注解官方文档:Hibernate Annotations

实体类注解详解JPA常见注解及使用

1.多主键定义

单一复合主键:

定义复合主键PK类,使用@IdClass主键引入该类即可使用。

//定义复合主键PK
public class CommonPK implements Serializable {

  private static final long serialVersionUID = 4360987061459461270L;

  private String userId;

  private String twoId;
}

//使用@IdClass主键引入复合主键:
@Entity
@Table(name = "TBL_USER")
@IdClass(CommonPK.class)
public class TblUser implements Serializable {

  private static final long serialVersionUID = 4360987061459461270L;

  @Column(nullable = false, name = "NAME")
  private String name;

  @Column(name = "Age")
  private Integer age;

  @Id
  @Column(nullable = false, name = "ID")
  @GeneratedValue(generator = "uuid")
  @GenericGenerator(name = "uuid", strategy = "uuid2")
  private String userId;

  @Id
  @Column(nullable = false, name = "TWOID")
  private String twoId;
}

复合主键中依赖其他表复合主键:

复合主键中依赖外键:其他表的复合主键:作为主键。如下:

public class ManyPK implements Serializable {
    private static final long serialVersionUID = 4360987061459461270L;

    @Column(name = "TASK_ID", length = 36, nullable = false)
    private String taskId;

    @Column(name = "USER_ID",length = 36)
    private String userEntityId;

    @Column(name = "USER_ID_TASK_ID",length = 36)
    private String userIdTaskId;


    @Column(name = "VALUE_ID",length = 36)
    private String valueEntityId;

    @Column(name = "VALUE_TASK_ID",length = 36)
    private String valueIdTaskId;
}


@Entity
@Table(name = "TBL_USER")
@IdClass(ManyPK.class)
public class TblMany implements Serializable {

  private static final long serialVersionUID = 4360987061459461270L;

  @Column(nullable = false, name = "NAME")
  private String name;

  @Column(name = "NUM")
  private Integer num;
    
  @Id
  @Column(name = "USER_ID",length = 36)
  private String userEntityId;
    
  @Id
  @Column(name = "USER_ID_TASK_ID",length = 36)
  private String userIdTaskId;

  @Id
  @Column(name = "VALUE_ID",length = 36)
  private String valueEntityId;

  @Id
  @Column(name = "VALUE_TASK_ID",length = 36)
  private String valueIdTaskId
    
  @ManyToOne
  @JoinColumns({
    @JoinColumn(name = "USER_ID", referencedColumnName = "ID", insertable = false, updatable = false),
    @JoinColumn(name = "USER_TASK_ID", referencedColumnName = "TASK_ID", insertable = false, updatable = false)
  })
  private TblUser userId;

  @ManyToOne
  @JoinColumns({
    @JoinColumn(name = "VALUE_ID", referencedColumnName = "ID", insertable = false, updatable = false),
    @JoinColumn(name = "VALUE_TASK_ID", referencedColumnName = "TASK_ID", insertable = false, updatable = false)
  })
  private TblValue valueId;
    
}

jpa复合主键常见报错问题:

1.如果使用@IdClass主键,同时又使用双层@MappedSuperclass注解会报错,无法获取属性

如下代码:继承了两个@MappedSuperclass注解类,运行时会报错。

@Entity
@Table(name = "TBL_USER")
@IdClass(CommonPK.class)
public class TblUser extends DatetimeEntity implements Serializable {

  private static final long serialVersionUID = 4360987061459461270L;

  @Column(nullable = false, name = "NAME")
  private String name;

  @Column(name = "Age")
  private Integer age;
}

@MappedSuperclass
public DatetimeEntity extends CommonEntity implements Serializable{
  private static final long serialVersionUID = 4360987061459461270L;
  @Column(nullable = false, name = "CREATE_DATE")
  private LocalDateTime createDate;
}
@MappedSuperclass
public CommonEntity implements Serializable{
  private static final long serialVersionUID = 4360987061459461270L;

  @Id
  @Column(nullable = false, name = "ID")
  @GeneratedValue(generator = "uuid")
  @GenericGenerator(name = "uuid", strategy = "uuid2")
  private String id;
}

@MappedSuperclass注解:

一般作为基类的注解,

@MappedSuperclass注解,通过这个注解,我们可以将该实体类当成基类实体,它不会隐射到数据库表,但继承它的子类实体在隐射时会自动扫描该基类实体的隐射属性,添加到子类实体的对应数据库表中。

使用环境:

1.@MappedSuperclass注解使用在父类上面,是用来标识父类的

2.@MappedSuperclass标识的类表示其不能映射到数据库表,因为其不是一个完整的实体类,但是它所拥有的属性能够隐射在其子类对用的数据库表中

3.@MappedSuperclass标识的类不能再有@Entity或@Table注解

2.复合主键中依赖其他表复合主键按以下代码写法会报错

public class ManyPK implements Serializable {
    private static final long serialVersionUID = 4360987061459461270L;

    @Column(name = "TASK_ID", length = 36, nullable = false)
    private String taskId;

    @ManyToOne
    @JoinColumns({
    @JoinColumn(name = "USER_ID", referencedColumnName = "ID", insertable = false, updatable = false),
    @JoinColumn(name = "USER_TASK_ID", referencedColumnName = "TASK_ID", insertable = false, updatable = false)
  })
  private TblUser userId;

  @ManyToOne
  @JoinColumns({
    @JoinColumn(name = "VALUE_ID", referencedColumnName = "ID", insertable = false, updatable = false),
    @JoinColumn(name = "VALUE_TASK_ID", referencedColumnName = "TASK_ID", insertable = false, updatable = false)
  })
  private TblValue valueId;
}

@Entity
@Table(name = "TBL_USER")
@IdClass(ManyPK.class)
public class TblMany implements Serializable {

  private static final long serialVersionUID = 4360987061459461270L;

  @Column(nullable = false, name = "NAME")
  private String name;

  @Column(name = "NUM")
  private Integer num;
    
  @Id
  @ManyToOne
  @JoinColumns({
    @JoinColumn(name = "USER_ID", referencedColumnName = "ID", insertable = false, updatable = false),
    @JoinColumn(name = "USER_TASK_ID", referencedColumnName = "TASK_ID", insertable = false, updatable = false)
  })
  private TblUser tblUser;

  @Id
  @ManyToOne
  @JoinColumns({
    @JoinColumn(name = "VALUE_ID", referencedColumnName = "ID", insertable = false, updatable = false),
    @JoinColumn(name = "VALUE_TASK_ID", referencedColumnName = "TASK_ID", insertable = false, updatable = false)
  })
  private TblUser tblUser;
    
}

报错如下:可按上面示例写法解决该问题

-Cannot convert value of type 'com.test.entity.ManyPK' to required type 'com.test.entity.TblMany' for property 'userId':
no matching editors or conversion strategy found"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雁过留声--

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值