146

( JPAJava Persistence API) 规范有 2 种不同的方式来指定实体复合键:@IdClass@EmbeddedId.

我在我的映射实体上使用了这两个注释,但对于不太熟悉JPA.

我只想采用一种方式来指定复合键。哪一个真的是最好的?为什么?

4

7 回答 7

107

我认为这@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. 但大多数情况下,从查询中了解给定字段是组合键的一部分是非常有用的。

于 2008-10-17T14:27:03.720 回答
24

使用复合主键的三种策略:

  • 将其标记为@Embeddable并向您的实体类添加一个普通属性,标记为@Id.
  • 为您的实体类添加一个普通属性,用@EmbeddedId.
  • 为实体类的所有字段添加属性,用 标记它们,用@Id标记实体类@IdClass,提供主键类的类。

使用@Id带有标记为的类@Embeddable是最自然的方法。无论如何,该@Embeddable标签都可用于非主键可嵌入值。它允许您将复合主键视为单个属性,并允许@Embeddable在其他表中重用该类。

下一个最自然的方法是使用@EmbeddedId标签。在这里,主键类不能用于其他表,因为它不是@Embeddable实体,但它确实允许我们将键视为某个类的单个属性。

最后,使用@IdClass@Id注释允许我们使用实体本身的属性映射复合主键类,这些属性对应于主键类中的属性名称。名称必须对应(没有覆盖它的机制),并且主键类必须履行与其他两种技术相同的义务。这种方法的唯一优点是它能够从封闭实体的接口“隐藏”主键类的使用。注解接受一个 Class 类型的 value 参数,该@IdClass参数必须是要用作复合主键的类。与要使用的主键类的属性对应的字段都必须用 注释@Id

参考: http: //www.apress.com/us/book/9781430228509

于 2017-02-13T21:38:48.270 回答
17

我发现了一个实例,我必须使用 EmbeddedId 而不是 IdClass。在这种情况下,有一个定义了附加列的连接表。我尝试使用 IdClass 来表示明确表示连接表中的行的实体的键来解决这个问题。我无法让它以这种方式工作。值得庆幸的是,“Java Persistence With Hibernate”有一个专门讨论这个主题的部分。一个提议的解决方案与我的非常相似,但它使用 EmbeddedId 代替。我按照书中的对象建模了我的对象,它现在可以正常运行。

于 2008-10-17T19:05:06.903 回答
14

据我所知,如果您的复合 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;
    }
}
于 2013-09-19T09:11:18.410 回答
8

我认为主要优点是我们可以@GeneratedValue在使用@IdClass? 我确定我们不能使用@GeneratedValuefor @EmbeddedId

于 2011-01-12T19:15:28.393 回答
6

复合键在使用时不能有@Id属性@EmbeddedId

于 2014-08-30T06:24:55.027 回答
2

使用 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

于 2018-04-02T17:20:35.163 回答