我应该使用哪个注释:@IdClass 或 @EmbeddedId

Posted

技术标签:

【中文标题】我应该使用哪个注释:@IdClass 或 @EmbeddedId【英文标题】:Which annotation should I use: @IdClass or @EmbeddedId 【发布时间】:2010-09-17 18:16:33 【问题描述】:

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

我在我的映射实体上使用了这两个注释,但对于那些不太熟悉JPA 的人来说,这真是一团糟。

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

【问题讨论】:

【参考方案1】:

我认为@EmbeddedId 可能更冗长,因为使用@IdClass 您无法使用任何字段访问运算符访问整个主键对象。使用@EmbeddedId 你可以这样做:

@Embeddable class EmployeeId  name, dataOfBirth 
@Entity class Employee 
  @EmbeddedId EmployeeId employeeId;
  ...

这给出了构成组合键的字段的清晰概念,因为它们都聚合在一个通过字段访问运算符访问的类中。

@IdClass@EmbeddedId 的另一个区别是在编写 HQL 时:

@IdClass 你写:

从员工 e 中选择 e.name

@EmbeddedId 你必须写:

从员工 e 中选择 e.employeeId.name

您必须为同一个查询编写更多文本。有些人可能会争辩说,这与IdClass 所提倡的更自然的语言不同。但大多数情况下,直接从查询中了解给定字段是复合键的一部分是非常有用的。

【讨论】:

虽然我同意上面给出的解释,但我还想为@IdClass 添加一个独特的用例,尽管在大多数情况下我更喜欢@EmbeddedId(从 Antonio 的一次会议中了解这一点Goncalves。他建议我们可以使用@IdClass,以防复合键类不可访问或来自另一个模块或无法添加注释的遗留代码。在这些情况下@IdClass会给我们一个我们的方式。 我认为使用@Gaurav 给出的@IdClass 注释的情况可能是JPA 规范列出了创建复合键的两种方法的原因。@IdClass 和@987654336 @【参考方案2】:

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

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

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

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

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

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

据我所知,如果您的复合 PK 包含 FK,则使用@IdClass 会更容易、更直接

使用@EmbeddedId,您必须为您的FK 列定义映射两次,一次在@Embeddedable 中,一次在@ManyToOne 中,其中@ManyToOne 必须是只读的(@PrimaryKeyJoinColumn),因为您可以'没有在两个变量中设置一列(可能发生冲突)。 所以你必须在@Embeddedable中使用一个简单的类型来设置你的FK。

在另一个使用@IdClass的站点上,这种情况可以更容易处理,如Primary Keys through OneToOne and ManyToOne Relationships所示:

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;
    

【讨论】:

别忘了给你的PK类添加getter @Sonata 为什么我们需要吸气剂?我在没有任何 getter/setter 的情况下尝试了它,它工作正常 感谢 id 类示例!虽然我最终也需要实现 Serializable 。还不如添加 getter 和 setter,特别是如果您的 IDE 可以自动生成它们。【参考方案5】:

我认为主要优点是我们可以在使用@IdClass 时使用@GeneratedValue 作为id?我确定我们不能将@GeneratedValue 用于@EmbeddedId

【讨论】:

Embeddedid中不能使用@GeneratedValue吗?? 我已经成功地将它与 EmbeddedId 一起使用,但显然它的支持因数据库而异。将它与 IdClass 一起使用也是如此。规范说:“GeneratedValue 注释只能可移植地用于简单(即非复合)主键。”【参考方案6】:

当使用@EmbeddedId 时,复合键不能有@Id 属性。

【讨论】:

【参考方案7】:

使用 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 的操作

【讨论】:

以上是关于我应该使用哪个注释:@IdClass 或 @EmbeddedId的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate 中的 idclass mapping 问题

当执行器处于活动状态时,我应该使用哪个注释来防止弹簧引导保护我的控制器

当执行器处于活动状态时,我应该使用哪个注释来防止弹簧引导保护我的控制器

IdClass 未在类“Hello”中定义

JPA:我应该使用哪个?基本(可选)或列(可为空)?

哪个更适合专业使用(web.xml(部署描述符)或@WebServlet注释?[关闭]