类 与 JPA 的关系

Classes Relationships with JPA

我有一组 Java classes 具有以下 UML 图:

 public class Invoice {
           @Id
          private long id;
...
        }

public class InvoiceDetail {
          @Id
          private long id;
          ...
          private String productName;
          private int quantity;
          private double price;

        }

我的目的是使用 JPA 注释来建立它们之间的不同关系。 Invoice和InvoiceDetail之间存在一种组合关系,即resolved分别对Invoice和InvoiceDetail使用@Embedded和@Embeddable注解。但是,在建立 InvoiceDetail、Class3 和 Class4 之间的关系时会出现问题。在这些关系中,InvoiceDetail 必须注释为@Entity。但是,当一个class与@Entity和@Embeddable同时注解时,对应的服务器在部署时会抛出运行时错误。 根据这个website的信息,我写了以下可能的解决方案:

@Entity
public class Invoice {
  @Id
  private long id;
  ...
  @ElementCollection
  @CollectionTable(name="INVOICEDETAIL", joinColumns=@JoinColumn(name="INVOICE_ID"))
  private List<InvoiceDetail> invoiceDetails;
  ...
}

这样可以解决我的问题吗?

提前致谢。

虽然不知道 classes 到底是什么很难说,但我想你有设计问题。 Class1 和 Class2 之间的组合表示任何 Class2 实例仅存在于对应的 Class1 实例的生命周期内。但另一方面,您有 Class3 实例和 Class4 实例,它们可以/必须与 Class2 实例有关系。

我想说的是,在我看来,Class1和Class2之间的关系应该是简单的关联,而不是组合。按照这条路径,Class2 将成为 JPA 中的一个实体,然后您的问题应该得到解决。

我通常将@Embeddable 用于class 那些实例永远不存在的实例,而@Entity 用于任何class 实例可以在没有其他实例的情况下存在的实例。例如,地址可以以任何一种方式实现,但不能在同一系统上实现。如果我不想 link 地址,地址将是 @Embeddable,但如果我想确保同一地址不保存在多行中,则它必须是 @Entity。


[编辑:在 classes 1 和 2 重命名为 Invoice 和 InvoiceDetails 之后添加]

在 Invoice 和 InvoiceDetails 之间进行组合非常有意义。但我仍然认为您应该避免对 InvoiceDetails 的双重个性的需要。我可以想到两种解决方案(都是重构):

  1. 如果您更喜欢将 InvoiceDetails 作为 @Embeddable,您可以将 Class3 和 Class4 的关联更改为 Invoice 而不是 InvoiceDetails。 InvoiceDetails 仍然可以通过 Invoice 对象遍历。
  2. 如果您希望保持关联不变,您可以将 InvoiceDetails 声明为一个实体。您仍然可以通过级联删除来实现您的合成(请参阅 javax.persistence.CascadeType)。似乎 InvoiceDetails 已经有了它自己的 table,这可能是更好的选择。

我检查了我的 JPA 应用程序,没有发现任何相同的 class 是 @Entity 和 @Embeddable。老实说,我怀疑这是否可能,因为 official javadoc of @Embeddable 说:

Specifies a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity.

由于@Entity 有它自己的身份,您会尝试声明具有两个身份的同一个对象 - 这是行不通的。

[/edit]


[edit2:为解决方案提案 #2 添加代码]

这段代码应该在一些假设下工作(见下文)。这是 1:n-关系的双向导航的实现。

@Entity
public class Invoice {
  @Id
  private long id;

  @OneToMany(mappedBy="invoice", cascade = CascadeType.ALL)
  private List<InvoiceDetail> details;
}

@Entity
public class InvoiceDetails {
  @Id
  private long id;

  @ManyToOne
  @JoinColumn(name="invoice_id")
  private Invoice invoice;
}

假设:表的命名与实体相同,invoice_details table 的外键列名为 "invoice_id" 并且两个 table 都有一个主键列名为"id"。请注意,mappedBy-value "invoice" 指的是实体字段,而 name-value "invoice_id" 指的是数据库 table。 删除 Class3 或 Class4 实例仍引用其 InvoiceDetails 的 Invoice 对象时要小心 - 您必须先释放这些引用。

有关 JPA 的信息,请参阅这些资源:

[/edit]