我有一组带有以下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之间存在组合关系,resolved分别使用@Embedded和@Embeddable注释为Invoice和InvoiceDetail。但是,通过建立InvoiceDetail,Class3和Class4之间的关系会出现问题。在这些关系中,InvoiceDetail必须注释为@Entity。但是,当一个类与@Entity和@Embeddable同时注释时,相应的服务器将在部署期间抛出运行时错误。 基于此website的信息,我写了以下可能的解决方案:
@Entity
public class Invoice {
@Id
private long id;
...
@ElementCollection
@CollectionTable(name="INVOICEDETAIL", joinColumns=@JoinColumn(name="INVOICE_ID"))
private List<InvoiceDetail> invoiceDetails;
...
}
为了解决我的问题,这是正确的吗?
提前致谢。
答案 0 :(得分:1)
虽然不知道什么是真正的类,但很难说,我想你有一个设计问题。 Class1和Class2之间的组合表示任何Class2实例仅存在于相应Class1实例的生命周期内。但另一方面,你有Class3实例和Class4实例,它们/必须与Class2实例有关系。
我想说的是,从我的观点来看,Class1和Class2之间的关系应该是一个简单的关联,而不是一个组合。遵循此路径,Class2将成为JPA中的实体,然后您应该解决您的问题。
我通常将@Embeddable用于其实例从不存在的类,而@Entity用于其实例可以在没有其他实例的情况下存在的任何类。例如,地址可以以任何方式实现,但不能在同一系统上实现。如果我不想链接地址,地址将是@Embeddable,但如果我想确保相同的地址不保存在多行中,则必须是@Entity。
[编辑:在第1和第2课后重新命名为Invoice and InvoiceDetails]
在Invoice和InvoiceDetails之间进行合成非常有意义。但我仍然认为你应该避免InvoiceDetails需要双重人格。我可以想到两个解决方案(两个重构):
我检查了我的JPA应用程序,但没有发现同一个类是@Entity和@Embeddable。老实说,我怀疑这是否可行,因为official javadoc of @Embeddable说:
指定一个类,其实例存储为拥有实体的内在部分,共享实体的标识。
由于@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”是指实体字段,而name-value“invoice_id”是指数据库表。 删除InvoiceDetails仍然被Class3或Class4实例引用的Invoice对象时要小心 - 您必须先释放这些引用。
有关JPA的信息,请参阅以下资源:
[/编辑]