( JPA
Java Persistence API) 规范有 2 种不同的方式来指定实体复合键:@IdClass
和@EmbeddedId
.
我在我的映射实体上使用了这两个注释,但对于不太熟悉JPA
.
我只想采用一种方式来指定复合键。哪一个真的是最好的?为什么?
( JPA
Java Persistence API) 规范有 2 种不同的方式来指定实体复合键:@IdClass
和@EmbeddedId
.
我在我的映射实体上使用了这两个注释,但对于不太熟悉JPA
.
我只想采用一种方式来指定复合键。哪一个真的是最好的?为什么?
我认为这@EmbeddedId
可能更冗长,因为@IdClass
您无法使用任何字段访问运算符访问整个主键对象。使用@EmbeddedId
你可以这样做:
@Embeddable class EmployeeId { name, dataOfBirth }
@Entity class Employee {
@EmbeddedId EmployeeId employeeId;
...
}
这给出了构成复合键的字段的清晰概念,因为它们都聚合在一个通过字段访问运算符访问的类中。
@IdClass
与and的另一个区别@EmbeddedId
是在编写 HQL 时:
和@IdClass
你一起写:
从员工 e 中选择 e.name
和@EmbeddedId
你一起写:
从员工 e 中选择 e.employeeId.name
您必须为同一个查询编写更多文本。有些人可能会争辩说,这与一种更自然的语言(如IdClass
. 但大多数情况下,从查询中了解给定字段是组合键的一部分是非常有用的。
使用复合主键的三种策略:
@Embeddable
并向您的实体类添加一个普通属性,标记为@Id
.@EmbeddedId
.@Id
标记实体类@IdClass
,提供主键类的类。使用@Id
带有标记为的类@Embeddable
是最自然的方法。无论如何,该@Embeddable
标签都可用于非主键可嵌入值。它允许您将复合主键视为单个属性,并允许@Embeddable
在其他表中重用该类。
下一个最自然的方法是使用@EmbeddedId
标签。在这里,主键类不能用于其他表,因为它不是@Embeddable
实体,但它确实允许我们将键视为某个类的单个属性。
最后,使用@IdClass
和@Id
注释允许我们使用实体本身的属性映射复合主键类,这些属性对应于主键类中的属性名称。名称必须对应(没有覆盖它的机制),并且主键类必须履行与其他两种技术相同的义务。这种方法的唯一优点是它能够从封闭实体的接口“隐藏”主键类的使用。注解接受一个 Class 类型的 value 参数,该@IdClass
参数必须是要用作复合主键的类。与要使用的主键类的属性对应的字段都必须用 注释@Id
。
参考: http: //www.apress.com/us/book/9781430228509
我发现了一个实例,我必须使用 EmbeddedId 而不是 IdClass。在这种情况下,有一个定义了附加列的连接表。我尝试使用 IdClass 来表示明确表示连接表中的行的实体的键来解决这个问题。我无法让它以这种方式工作。值得庆幸的是,“Java Persistence With Hibernate”有一个专门讨论这个主题的部分。一个提议的解决方案与我的非常相似,但它使用 EmbeddedId 代替。我按照书中的对象建模了我的对象,它现在可以正常运行。
据我所知,如果您的复合 PK 包含 FK,则使用起来更容易、更直接@IdClass
@EmbeddedId
你必须为你的 FK 列定义一个映射两次,一次是一次@Embeddedable
,一次是因为你不能在两个变量中设置一个列(可能的冲突)。
所以你必须使用一个简单的类型来设置你的 FK 。@ManyToOne
@ManyToOne
@PrimaryKeyJoinColumn
@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
在使用@IdClass
? 我确定我们不能使用@GeneratedValue
for @EmbeddedId
。
复合键在使用时不能有@Id
属性@EmbeddedId
。
使用 EmbeddedId,您可以在 HQL 中使用 IN 子句,例如:FROM Entity WHERE id IN :ids
其中 id 是 EmbeddedId,而使用 IdClass 实现相同的结果很痛苦,您需要执行类似的操作FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN