Java 在hibernate中使用复合密钥
假设我想要一个复合键作为购买订单实体的street、city 下面是我如何确定这样做Java 在hibernate中使用复合密钥,java,hibernate,jpa,Java,Hibernate,Jpa,假设我想要一个复合键作为购买订单实体的street、city 下面是我如何确定这样做 @Embeddable public class BillingAddress implements Serializable { private String street; private String city; public BillingAddress(){ } public BillingAddr
@Embeddable
public class BillingAddress implements Serializable {
private String street;
private String city;
public BillingAddress(){
}
public BillingAddress(String street, String city) {
this.street = street;
this.city = city;
}
//with getters and setters
}
@Entity
@IdClass(BillingAddress.class)
public class PurchaseOrder {
public PurchaseOrder(BillingAddress billingAddress) {
street = billingAddress.getStreet();
city = billingAddress.getCity();
}
@Id
@AttributeOverrides({
@AttributeOverride(name = "street", column = @Column(name = "STREET")),
@AttributeOverride(name = "city", column = @Column(name = "CITY")) })
private String street;
private String city;
private String itemName;
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
}
我想了解@AttributeOverrides注释的真正含义是什么?即使我将column name改为something STREET1,我仍然可以看到使用列名称STREET创建的表。那么column=@column(name=“STREET”)在这里做什么呢
另外,我可以将其作为PurchaseOrder类的字段,而不是构造或获取BillingAddress
public class PurchaseOrder {
BillingAddress billingAddress;
}
在这种情况下,这将如何改变?
我是否还需要有私人字符串街;私人城市;按购买顺序
最后,我读到在新数据库系统设计中应该避免使用复合键,使用复合主键适用于这样一种情况:为了在不改变数据库表结构的情况下映射遗留数据库表,对吗?那句话有效吗
//编辑问题
保存账单地址在字段中的采购订单
PurchaseOrder purchaseOrder = new PurchaseOrder();
purchaseOrder.setItemName("name");
BillingAddress billingAddress = new BillingAddress();
billingAddress.setCity("c1"); billingAddress.setStreet("s1"); purchaseOrder.setBillingAddress(billingAddress);
session.save(purchaseOrder);
好的,您的
PurchaseOrder
类不会从任何类型的映射实体扩展,您(当前)应用@AttributeOverride
的属性也不会扩展。因此,实际上没有什么可以覆盖的,您的JPA提供者只是忽略注释。我认为您试图做的是为实体定义一个嵌入式id,同时覆盖该id的一些列映射。您可以通过对当前代码进行一些修改来实现这一点:
@Entity
public class PurchaseOrder {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "street", column = @Column(name = "BILLING_STREET")),
@AttributeOverride(name = "city", column = @Column(name = "BILLING_CITY")) })
private BillingAddress billingAddress;
private String itemName;
// Constructors, Getters/Setters
}
请注意,我已经更改了被覆盖属性的名称,因为在您当前的示例中,嵌入的id名称和被覆盖的名称是相同的。您问的问题很少,我尝试查看所有问题并回答每个问题: @AnnotationOverride做什么? 请回答: 第二个问题对我来说有点不清楚,但我想你是在问是否必须在PurchaseOrder类中包含组合键中的所有字段。 不,我不这么认为。下面是一个我快速拼凑的例子:
@Entity
@Table(name = "PURCHASE_ORDER")
public class PurchaseOrder{
@Id
private BillingAddress billingAddress;
//getters & setters
@Embeddable
public static class BillingAddress implements Serializable {
@Column(name = "street")
private String street;
@Column(name = "city")
private String city;
@Column(name = "itemName")
private String itemName;
//getters & setters
}
}
不要担心语法,只关心结构。您甚至可以在PurchaseOrder中添加额外字段,该字段不是id
我是否应该使用复合键?
在这里回答:我已经阅读了下面的文章,作者提到PurchaseOrder实体中的street和city字段,“当然,重复的代码是street和city的两个私有数据成员。创建复合密钥需要这种重复。”另外,如果PurhaseOrder和BillingAddress之间的关系在没有账单地址的情况下无法存在,该怎么办?(如果删除账单地址,则应删除场景中的采购订单)在这种情况下,我需要将账单地址传递给采购订单构造函数,而不是像您在代码中显示的那样将其作为字段?该教程似乎有一个错误-当使用@IdClass时,您需要映射所属实体中复合键的所有元素。对于你的第二个问题,JPA框架在保存实体之前会验证它们-这包括验证是否设置了嵌入式id。我从构造函数中删除了账单地址,并将其作为你的账单地址,但它给出了一个例外,“初始SessionFactory创建失败。org.hibernate.AnnotationException:在实体hello.domain.PurchaseOrder:线程“main”java.lang.ExceptionInInitializerRor中找不到@IdClass的属性”“我只是把street和city字段放在PurchaseOrder类中,然后用复合主键创建exception和PuchaseOrder表。但在保存采购订单时,它会给我以下异常,错误:“城市”列不能为空。请参阅编辑问题部分,了解我这次如何保存采购订单。