繁体   English   中英

与JPA的类关系

[英]Classes Relationships with JPA

我有一组具有以下UML图的Java类:

在此处输入图片说明

 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之间存在组成关系,可以分别使用@Embedded和@Embeddable批注分别解决 Invoice和InvoiceDetail的组成关系。 但是,通过建立InvoiceDetail,Class3和Class4之间的关系会出现问题。 在这些关系中,InvoiceDetail必须注释为@Entity。 但是,如果在与@Entity和@Embeddable同时注释一个类时,则相应的服务器将在部署期间引发运行时错误。 根据本网站的信息,我编写了以下可能的解决方案:

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

为了解决我的问题,这是正确的吗?

提前致谢。

尽管很难知道这些类的真正含义,但是我认为您有一个设计问题。 Class1和Class2之间的组合表明,任何Class2实例仅存在于相应Class1实例的生命周期内。 但是另一方面,您具有Class3实例和Class4实例,它们可以/必须与Class2实例具有关系。

我要说的是,从我的角度来看,Class1和Class2之间的关系应该是简单的关联,而不是组成。 遵循此路径,Class2将成为JPA中的一个Entity,那么您应该已解决了问题。

我通常将@Embeddable用于实例自身不存在的类,并将@Entity用于其实例可以不存在其他实例的任何类。 例如,可以以任何一种方式实现地址,但不能在同一系统上实现。 如果我不想链接地址,则地址为@Embeddable,但如果我想确保同一地址没有保存在多行中,则地址必须为@Entity。


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

在Invoice和InvoiceDetails之间有一个组合很有意义。 但是我仍然认为您应该避免InvoiceDetails具有双重性格。 我可以想到两种解决方案(两种重构):

  1. 如果您希望将InvoiceDetails设置为@Embeddable,则可以将Class3和Class4的关联更改为Invoice,而不是InvoiceDetails。 InvoiceDetails仍可通过Invoice对象遍历。
  2. 如果您希望保持原样的关联,则可以将InvoiceDetails声明为实体。 您仍然可以通过级联删除来实现合成(请参见javax.persistence.CascadeType)。 看来InvoiceDetails已经拥有了自己的表,所以这可能是更好的选择。

我检查了JPA应用程序,未发现@Entity和@Embeddable属于同一类。 老实说,我怀疑这是否有可能,因为@Embeddable官方javadoc说:

指定一个类,其实例存储为拥有实体的固有部分并共享该实体的标识

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

[/编辑]


[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表的外键列的名称为“ invoice_id”,两个表的主键列的名称均为“ id”。 请注意,mappedBy值“发票”是指实体字段,而名称值“ invoice_id”是指数据库表。 删除仍由您的Class3或Class4实例引用其InvoiceDetails的Invoice对象时要小心-您必须首先释放这些引用。

有关JPA的信息,请参考以下资源:

[/编辑]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM