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。但是,如果在与@Entity和@Embeddable同时注释一个类时,则相应的服务器将在部署期间引发运行时错误。
根据此website的信息,我编写了以下可能的解决方案:
@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具有双重性格。我可以想到两种解决方案(两种重构):
如果您希望将InvoiceDetails设置为@Embeddable,则可以将Class3和Class4的关联更改为Invoice,而不是InvoiceDetails。 InvoiceDetails仍可通过Invoice对象遍历。
如果您希望保持原样的关联,则可以将InvoiceDetails声明为实体。您仍然可以通过级联删除来实现合成(请参见javax.persistence.CascadeType)。看来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_id”是指数据库表。
删除仍由您的Class3或Class4实例引用其InvoiceDetails的Invoice对象时要小心-您必须首先释放这些引用。
有关JPA的信息,请参考以下资源:
The Java EE 7 Tutorial: Persistence
Wikibooks: Java Persistence
Javadoc of Package javax.persistence
[/编辑]