Java 在hibernate中使用复合密钥

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

假设我想要一个复合键作为购买订单实体的street、city

下面是我如何确定这样做

    @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表。但在保存采购订单时,它会给我以下异常,错误:“城市”列不能为空。请参阅编辑问题部分,了解我这次如何保存采购订单。