的JPA
(Java持久性API)规范有2名不同的方式来指定实体组合键:@IdClass
和@EmbeddedId
.
我在我的映射实体上使用了两个注释,但对于那些不熟悉的人来说,结果却是一团糟JPA
.
我想只采用一种方法来指定复合键.哪一个真的最好?为什么?
我认为这@EmbeddedId
可能更冗长,因为@IdClass
您无法使用任何字段访问运算符访问整个主键对象.使用@EmbeddedId
你可以这样做:
@Embeddable class EmployeeId { name, dataOfBirth } @Entity class Employee { @EmbeddedId EmployeeId employeeId; ... }
这给出了构成组合键的字段的清晰概念,因为它们都是在通过字段访问操作符访问的类中聚合的.
与另一个不同之处@IdClass
,并@EmbeddedId
是当它涉及到写HQL:
随@IdClass
你写:
select e.name from Employee e
和@EmbeddedId
你一起写:
select e.employeeId.name from Employee e
您必须为同一查询编写更多文本.有些人可能会认为这与一种更自然的语言不同,例如推广的语言IdClass
.但是大多数时候从查询中理解给定字段是复合键的一部分是非常宝贵的帮助.
我发现了一个必须使用EmbeddedId而不是IdClass的实例.在这种情况下,有一个连接表,其中定义了其他列.我尝试使用IdClass来解决此问题,以表示明确表示连接表中的行的实体的键.我无法以这种方式工作.值得庆幸的是"Java Persistence With Hibernate"有一节专门讨论这个主题.一个提议的解决方案与我的解决方案非常相似,但它使用的是EmbeddedId.我在书中的对象之后对我的对象进行了建模,现在它的行为正确.
使用复合主键有三种策略:
将其标记为@Embeddable
并为您的实体类添加标准属性,标记为@Id
.
添加到您的实体类的标准属性,标记为@EmbeddedId
.
在实体类中为其所有字段添加属性,标记它们@Id
,并用@IdClass
实际类标记,提供主键类的类.
@Id
标记为类的使用@Embeddable
是最自然的方法.@Embeddable
无论如何,该标记可用于非主键可嵌入值.它允许您将复合主键视为单个属性,并允许@Embeddable
在其他表中重用该类.
下一个最自然的方法是使用@EmbeddedId
标签.这里,主键类不能在其他表中使用,因为它不是@Embeddable
实体,但它确实允许我们将键视为某个类的单个属性.
最后,使用@IdClass
和@Id
注释允许我们使用与主键类中的属性名称相对应的实体本身的属性来映射复合主键类.名称必须对应(没有覆盖它的机制),主键类必须履行与其他两种技术相同的义务.这种方法的唯一优点是它能够从封闭实体的接口"隐藏"主键类的使用.的@IdClass
批注采用类类型的值参数,该参数必须是类被用作化合物主键.与要使用的主键类的属性对应的字段必须全部注释@Id
.
参考:http://www.apress.com/us/book/9781430228509
据我所知,如果你的复合PK包含FK,它使用起来更简单,更直接 @IdClass
随着@EmbeddedId
你必须定义映射为您的FK列两次,onece在@Embeddedable
一次用于为即@ManyToOne
其中@ManyToOne
已经被只读(@PrimaryKeyJoinColumn
),因为你不能有一列两个变量(可能发生的冲突)设置.
所以你必须使用简单的类型来设置你的FK @Embeddedable
.
在使用@IdClass
这种情况的另一个站点上可以更容易地处理,如主键通过OneToOne和ManyToOne关系所示:
示例JPA 2.0 ManyToOne id注释
... @Entity @IdClass(PhonePK.class) public class Phone { @Id private String type; @ManyToOne @Id @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID") private Employee owner; ... }
示例JPA 2.0 id类
... public class PhonePK { private String type; private long owner; public PhonePK() {} public PhonePK(String type, long owner) { this.type = type; this.owner = owner; } public boolean equals(Object object) { if (object instanceof PhonePK) { PhonePK pk = (PhonePK)object; return type.equals(pk.type) && owner == pk.owner; } else { return false; } } public int hashCode() { return type.hashCode() + owner; } }
我认为主要优点是我们可以在使用@GeneratedValue
时使用id @IdClass
?我敢肯定,我们不能用@GeneratedValue
了@EmbeddedId
.