我应该使用哪个注释:@IdClass或@EmbeddedId
JPA (Java持久性API)规范有两种不同的方式来指定实体组合键: @IdClass和@EmbeddedId 。
我在我的映射实体上使用了两个注释,但是对于不太熟悉JPA人来说却是一个大混乱。
我只想采用一种方法来指定组合键。 哪一个真的是最好的? 为什么?
我认为@EmbeddedId可能更为详细,因为使用@IdClass您无法使用任何字段访问运算符来访问整个主键对象。 使用@EmbeddedId你可以这样做:
@Embeddable class EmployeeId { name, dataOfBirth } @Entity class Employee { @EmbeddedId EmployeeId employeeId; ... }
这给出了构成组合键的字段的清晰概念,因为它们全部聚合在通过字段访问运算符访问的类中。
与@IdClass和@EmbeddedId另一个区别是编写HQL的时候:
用@IdClass你写:
从员工e中selecte.name
和@EmbeddedId你必须写:
从Employee e中selecte.employeeId.name
您必须为同一个查询编写更多文本。 有些人可能会认为,这与IdClass提倡的更自然的语言不同。 但大多数时候从查询中理解给定的字段是组合键的一部分是非常有帮助的。
我发现了一个实例,我不得不使用EmbeddedId而不是IdClass。 在这种情况下有一个连接表具有其他列定义。 我试图用IdClass来解决这个问题,以表示显式表示连接表中的行的实体的键。 我不能这样工作。 幸运的是“Java持久化与hibernate”有一个专门讨论这个话题的部分。 一个build议的解决scheme非常类似于我的,但它使用EmbeddedId来代替。 我在书中的对象之后,对它们的行为进行了正确的模拟。
据我所知,如果你的复合PK包含FK,使用@IdClass更简单,更直接
使用@EmbeddedId你必须定义两次你的FK列映射,一次在@Embeddedable和一次为@ManyToOne其中@ManyToOne必须是只读的( @PrimaryKeyJoinColumn ),因为你不能有一个列设置在两个variables(可能的冲突)。
所以你必须在@Embeddedable使用简单的types来设置你的FK。
在使用@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; } }
我认为最主要的优点是我们可以在使用@IdClass时使用@GeneratedValue作为id。 我确定我们不能在@EmbeddedId使用@GeneratedValue 。
有三种策略可以使用复合主键:
- 将其标记为
@Embeddable并为您的实体类添加一个标准属性,标记为@Id。 - 添加到您的实体类的正常属性,用
@EmbeddedId标记。 - 将属性添加到您的实体类的所有字段,用
@Id标记它们,并用@IdClass标记实体类,提供您的主键类的类。
将@Id与标记为@Embeddable的类@Embeddable是最自然的方法。 @Embeddable标签可以用于非主键可embedded值。 它允许您将复合主键作为单个属性来处理,并允许在其他表中重用@Embeddable类。
接下来最自然的方法是使用@EmbeddedId标签。 在这里,主键类不能用在其他表中,因为它不是@Embeddable实体,但它允许我们把键作为某个类的单个属性。
最后,使用@IdClass和@Id注释允许我们使用与主键类中的属性名相对应的实体本身的属性来映射复合主键类。 名字必须一致(没有重写这个的机制),主键类必须遵守与其他两种技术相同的义务。 这种方法的唯一好处是能够从封闭实体的接口“隐藏”主键类的使用。 @IdClass批注采用Classtypes的值参数,该参数必须是要用作复合主键的类。 对应于要使用的主键类的属性的字段必须全部用@Id注释。
参考: http : //www.apress.com/us/book/9781430228509
使用@EmbeddedId时,复合键不能具有@Id属性。