要映射复合键,您可以使用EmbeddedId
or the IdClass
注释。我知道这个问题并不严格涉及 JPA,但规范定义的规则也适用。所以他们在这里:
2.1.4 主键和实体身份
...
复合主键必须
对应于单个
持久字段或属性或
此类字段或属性的集合
如下面所描述的。主键类
必须定义为代表一个
复合主键。合成的
主键通常出现在以下情况
当从遗留数据库映射
数据库密钥由几个组成
列。The EmbeddedId
and
IdClass
注释用于
表示复合主键。看
第 9.1.14 和 9.1.15 节。
...
以下规则适用
复合主键:
- 主键类必须是公共的并且必须具有公共无参数
构造函数。
- 如果使用基于属性的访问,则主键的属性
类必须是公共的或受保护的。
-
主键类必须是
serializable
.
-
主键类
必须定义
equals
and hashCode
方法。值的语义
这些方法的相等性必须是
与数据库相等性一致
对于数据库类型
键已映射。
- 复合主键必须被表示和映射为
可嵌入类(参见第 9.1.14 节,
“EmbeddedId Annotation”)或者必须是
表示并映射到多个
实体的字段或属性
类(参见第 9.1.15 节,“IdClass
注解”)。
- 如果复合主键类映射到多个字段或
实体类的属性,
主键字段的名称或
主键类中的属性
并且实体类的那些必须
对应并且它们的类型必须是
相同的。
With an IdClass
复合主键的类可能如下所示(可能是静态内部类):
public class TimePK implements Serializable {
protected Integer levelStation;
protected Integer confPathID;
public TimePK() {}
public TimePK(Integer levelStation, Integer confPathID) {
this.levelStation = levelStation;
this.confPathID = confPathID;
}
// equals, hashCode
}
和实体:
@Entity
@IdClass(TimePK.class)
class Time implements Serializable {
@Id
private Integer levelStation;
@Id
private Integer confPathID;
private String src;
private String dst;
private Integer distance;
private Integer price;
// getters, setters
}
The IdClass
注解将多个字段映射到表 PK。
With EmbeddedId
复合主键的类可能如下所示(可能是静态内部类):
@Embeddable
public class TimePK implements Serializable {
protected Integer levelStation;
protected Integer confPathID;
public TimePK() {}
public TimePK(Integer levelStation, Integer confPathID) {
this.levelStation = levelStation;
this.confPathID = confPathID;
}
// equals, hashCode
}
和实体:
@Entity
class Time implements Serializable {
@EmbeddedId
private TimePK timePK;
private String src;
private String dst;
private Integer distance;
private Integer price;
//...
}
The @EmbeddedId
注释将 PK 类映射到表 PK。
差异:
- 从物理模型来看,没有区别
-
@EmbeddedId
以某种方式更清楚地传达了钥匙是复合钥匙并且 IMO 是有道理的当组合的 pk 本身是有意义的实体或在代码中重用时.
-
@IdClass
用于指定某些字段组合是唯一的,但这些组合没有特殊含义.
它们还会影响您编写查询的方式(使它们或多或少变得冗长):
参考
- JPA 1.0 specification
- 第2.1.4节“主键和实体身份”
- 第 9.1.14 节 “EmbeddedId 注释”
- 第9.1.15节“IdClass注释”