@Embeddable和@Entity在映射集合方面的区别

18

这可能有点幼稚,但我对何时使用@Entity@Embeddable有疑问。

假设我有一个UserNotification类。

 @Entity
 public class User{
     //other properties
     @onetomany
     private List<Notification> notifications;
 }

 @Entity
 public class Notification{
     //properties
 }
我明白 UserNotification 会有对应的表,还有第三张用于映射的表。 如果我这样做会怎么样?
 @Entity
 public class User {
     //other properties
     @ElementCollection
     private List<Notification> notifications;
 }

 @Embeddable
 public class Notification{
     //properties
 }

我知道这不会为 Notification 创建一个表格。但我仍然可以存储我的通知对象。我查阅了文档,但还有一些疑问:

  1. 这是否基于我是否想将类B视为单独的表格?
  2. 创建表格和可嵌入对象之间是否有性能差异?
  3. 除了直接查询表格外,使用可嵌入对象不能做什么?

对于任何阅读此问题的人,这个问题也可能对您有所帮助。

2个回答

11
  1. 是否基于我是否想将B类视为单独的表来确定?

是的,当您使用@Embedded时,您会将该@Embeddable实体嵌入到@Entity类中,在同一张@Entity类的表中添加嵌入实体的列。

  1. 创建表和嵌入式对象之间是否存在性能差异?

当您使用@Embedded时,需要一个查询来创建表,同时插入和选择一行。但是如果您不使用它,则需要多个查询,因此,使用@Embedded可以提高性能。

  1. 除了直接查询表之外,我不能用嵌入式对象做什么事情,而可以用表做什么事情?

可能是删除相应的嵌入式实体,但这可能会导致完整性约束冲突。


我想我可以使用Embeddable与ElementCollection。我不需要使用@Embedded,对吗? - shazinltc
1
第三点:考虑到Person包含Address(嵌入式),如果两者有单独的表,您可以直接删除相关联的地址,但是如果Person的表具有对地址的外键引用,这可能会导致完整性约束违规。 - deepakraut
'@Embeddable'使类适合嵌入。 '@Embedded'实际上嵌入了可嵌入的实体。 - deepakraut
这个链接提供了关于嵌入式和可嵌入对象的很好的解释。 - deepakraut

0
在JPA中,有几种方法可以创建复合键字段。让我们看看使用@Embeddable注释的方法。
让我们从实体类开始。
@Entity
@Table
public class TraceRecord {
    @Id
    private TraceRecordPk id;

    @Version
    @Transient
    private int version;

    @Column(columnDefinition = "char")
    private String durationOfCall;

    @Column(columnDefinition = "char")
    private String digitsDialed;

    @Column(columnDefinition = "char")
    private String prefixCalled;

    @Column(columnDefinition = "char")
    private String areaCodeCalled;

    @Column(columnDefinition = "char")
    private String numberCalled;
}

这是一个相当简单的实体类,其中包含@Id和@Version字段以及一些@Column定义。不详细介绍,您会发现@Version字段也被注释为@Transient。我之所以这样做,只是因为我的表也没有用于跟踪版本的列,但我的数据库已经记录了,所以我对版本控制并不太担心。您还会注意到@Column字段在columnDefinition属性上设置了“char”的值。这是因为我的表中的字段被定义为char而不是varchar。如果它们是varchar,我就不需要这样做,因为String默认映射到varchar字段。
@Id字段是我现在感兴趣的内容。它不是标准的Java类型,而是我自己定义的类。以下是该类。
@Embeddable
public class TraceRecordPk implements Serializable {

    private static final long serialVersionUID = 1L;

    @Temporal(TemporalType.DATE)
    @Column
    private Date dateOfCall;

    @Column(columnDefinition="char")
    private String timeOfCall;

    @Column(columnDefinition="char")
    private String callingParty;

    /**
     * Constructor that takes values for all 3 members.
     *
     * @param dateOfCall Date the call was made
     * @param timeOfCall Time the call was made
     * @param callingParty Extension from which the call originated
     */
    public TraceRecordPk(Date dateOfCall, String timeOfCall, String callingParty) {
        this.dateOfCall = dateOfCall;
        this.timeOfCall = timeOfCall;
        this.callingParty = callingParty;
    }
}

为了使这个类能够成为实体类上的@Id字段,它需要像我之前提到的那样被注释为@Embeddable。我选择的三个字段只是普通的@Column定义。我没有为每个字段创建getter/setter,而是实现了一个构造函数,该构造函数接受所有3个字段的值,使任何实例都是不可变的。当用@Embeddable注释一个类时,该类将需要实现Serializable。因此,我添加了一个默认的serialVersionUID来适应。
现在你已经创建了一个带有@Embeddable注释的类,你可以将其作为实体类中@Id字段的类型使用。简单吧。

谢谢,但我已经阅读了这篇文章。它并没有回答我的问题。我的问题与复合键无关。 - shazinltc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接