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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/212350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:26:26  来源:igfitidea点击:

Which annotation should I use: @IdClass or @EmbeddedId

javajpaannotationsjava-persistence-api

提问by sakana

The JPA(Java Persistence API) specification has 2 different ways to specify entity composite keys: @IdClassand @EmbeddedId.

JPA(Java持久性API)规范有2名不同的方式来指定实体组合键:@IdClass@EmbeddedId

I'm using both annotations on my mapped entities, but it turns out to be a big mess to people who aren't very familiar with JPA.

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

I want to adopt only one way to specify composite keys. Which one is really the best? Why?

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

采纳答案by Jorge Ferreira

I consider that @EmbeddedIdis probably more verbose because with @IdClassyou cannot access the entire primary key object using any field access operator. Using the @EmbeddedIdyou can do like this:

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

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

This gives a clear notion of the fields that make the composite key because they are all aggregated in a class that is accessed trough a field access operator.

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

Another difference with @IdClassand @EmbeddedIdis when it comes to write HQL :

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

With @IdClassyou write:

@IdClass你一起写:

select e.name from Employee e

and with @EmbeddedIdyou have to write:

@EmbeddedId你必须写:

select e.employeeId.name from Employee e

You have to write more text for the same query. Some may argue that this differs from a more natural language like the one promoted by IdClass. But most of the times understanding right from the query that a given field is part of the composite key is of invaluable help.

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

回答by laz

I discovered an instance where I had to use EmbeddedId instead of IdClass. In this scenario there is a join table that has additional columns defined. I attempted to solve this problem using IdClass to represent the key of an entity that explicitly represents rows in the join table. I couldn't get it working this way. Thankfully "Java Persistence With Hibernate" has a section dedicated to this topic. One proposed solution was very similar to mine but it used EmbeddedId instead. I modeled my objects after those in the book it now behaves correctly.

我发现了一个必须使用 EmbeddedId 而不是 IdClass 的实例。在这种情况下,有一个连接表定义了额外的列。我尝试使用 IdClass 来表示实体的键来解决这个问题,该实体显式表示连接表中的行。我无法让它以这种方式工作。谢天谢地,“Java Persistence With Hibernate”有一节专门讨论这个主题。一个提议的解决方案与我的非常相似,但它使用了 EmbeddedId。我按照书中的对象建模我的对象,现在它的行为是正确的。

回答by bertie

I think the main advantage is that we could use @GeneratedValuefor the id when using the @IdClass? I'm sure we can't use @GeneratedValuefor @EmbeddedId.

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

回答by Ondrej Bozek

As far as i know if your composite PK contains FK it's easier and more straightforward to use @IdClass

据我所知,如果您的复合 PK 包含 FK,则使用起来更简单、更直接 @IdClass

With @EmbeddedIdyou have to define mapping for your FK column twice, onece in @Embeddedableand once for as i.e. @ManyToOnewhere @ManyToOnehas to be read-only(@PrimaryKeyJoinColumn) because you can't have one column set in two variables (possible conflicts).
So you have to set your FK using simple type in @Embeddedable.

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

On the other site using @IdClassthis situation can be handled much easier as shown in Primary Keys through OneToOne and ManyToOne Relationships:

在另一个站点上,使用@IdClass这种情况可以更容易地处理,如通过 OneToOne 和 ManyToOne 关系的主键所示:

Example JPA 2.0 ManyToOne id annotation

示例 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;
    ...
}

Example JPA 2.0 id class

示例 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;
    }
}

回答by B.K

Composite Key must not have an @Idproperty when @EmbeddedIdis used.

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

回答by Adelin

There are three strategies to use a compound primary key:

使用复合主键有以下三种策略:

  • Mark it as @Embeddableand add to your entity class a normal property for it, marked with @Id.
  • Add to your entity class a normal property for it, marked with @EmbeddedId.
  • Add properties to your entity class for all of its fields, mark them with @Id,and mark your entity class with @IdClass, supplying the class of your primary key class.
  • 将其标记为@Embeddable并将其添加到您的实体类的正常属性,标记为@Id.
  • 为实体类添加一个普通属性,标有@EmbeddedId.
  • 将属性添加到您的实体类的所有字段,用 标记它们@Id,并用 标记您的实体类@IdClass,提供主键类的类。

The use of @Idwith a class marked as @Embeddableis the most natural approach. The @Embeddabletag can be used for non-primary key embeddable values anyway. It allows you to treat the compound primary key as a single property, and it permits the reuse of the @Embeddableclass in other tables.

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

The next most natural approach is the use of the @EmbeddedIdtag. Here, the primary key class cannot be used in other tables since it is not an @Embeddableentity, but it does allow us to treat the key as a single attribute of some class.

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

Finally, the use of the @IdClassand @Idannotations allows us to map the compound primary key class using properties of the entity itself corresponding to the names of the properties in the primary key class. The names must correspond (there is no mechanism for overriding this), and the primary key class must honor the same obligations as with the other two techniques. The only advantage to this approach is its ability to “hide” the use of the primary key class from the interface of the enclosing entity. The @IdClassannotation takes a value parameter of Class type, which must be the class to be used as the compound primary key. The fields that correspond to the properties of the primary key class to be used must all be annotated with @Id.

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

Reference: http://www.apress.com/us/book/9781430228509

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

回答by Aleks Ben Maza

With EmbeddedId you can use the IN clause in HQL, for example : FROM Entity WHERE id IN :idswhere id is an EmbeddedId whereas it's pain to achieve the same result with IdClass you will want to do something like FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN

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