在休眠中使用复合键

Posted

技术标签:

【中文标题】在休眠中使用复合键【英文标题】:using composite key with hibernate 【发布时间】:2013-01-03 01:55:46 【问题描述】:

假设我想要一个复合键作为采购订单实体的街道、城市。

以下是我如何识别它,

    @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 注解真正的作用是什么?即使我将列名更改为 STREET1,我仍然看到使用列名 STREET 创建的表。那么 column = @Column(name = "STREET")) 在这里做什么。

除了使用 BillingAddress 的构造函数之外,我还可以像 PurchaseOrder 类的字段一样拥有它,

 public class PurchaseOrder 
     BillingAddress billingAddress;


在这种情况下,这将如何改变? 我还需要私人字符串街吗?私人字符串城市;在 PurchaseOrder 中?

最后我读到,在新的数据库系统设计中应该避免使用复合键,在这种情况下使用复合主键适用于在不改变数据库表结构的情况下映射遗留数据库表的情况,对吗?该声明有效吗?

//编辑问题

在字段中保存账单地址所在的采购订单,

PurchaseOrder purchaseOrder = new PurchaseOrder();
purchaseOrder.setItemName("name");

BillingAddress billingAddress = new BillingAddress();
billingAddress.setCity("c1"); billingAddress.setStreet("s1");                                                              purchaseOrder.setBillingAddress(billingAddress); 
session.save(purchaseOrder);

【问题讨论】:

【参考方案1】:

你问的问题很少,我试着把所有的问题都回答一遍:

@AnnotationOverride 有什么作用?

在这里回答:What does @AttributeOverride mean?

第二个问题对我来说有点不清楚,但我想您是在问是否必须在 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 的额外字段。

我应该使用复合键吗?

在这里回答:Should I use composite primary keys or not?

【讨论】:

【参考方案2】:

好吧,您的 PurchaseOrder 类不会从任何类型的映射实体扩展,您(当前)应用@AttributeOverrides 的属性也不会扩展。因此,没有什么可以真正覆盖,您的 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 名称和覆盖的名称是相同的。

【讨论】:

我在下面的文章中提到了关于 PurchaseOrder 实体中的街道和城市字段的文章,“重复的代码当然是街道和城市的两个私有数据成员。这个重复是必需的创建复合键。” ibm.com/developerworks/library/os-hibernatejpa 另外,如果PurhaseOrder 和BillingAddress 之间的关系在没有帐单地址的情况下不存在PuchaseOrder 的情况下怎么办。(如果您删除帐单地址采购订单应该被删除方案的kinf)在那种情况下我需要将帐单地址传递给采购订单构造函数,而不是像您在代码中显示的那样将其作为字段? 该教程似乎有一个错误 - 使用 @IdClass 时,您需要在拥有实体中映射复合键的所有元素。对于您的第二个问题,JPA 框架会在保存实体之前对其进行验证 - 这包括验证嵌入的 id 是否已设置。 我从构造函数中删除了帐单地址并将其设为您的,但它给出了一个例外,“初始 SessionFactory 创建失败.org.hibernate.AnnotationException:@IdClass 的属性在实体 hello.domain 中找不到.PurchaseOrder:线程“main”中的城市异常 java.lang.ExceptionInInitializerError” 我只是将字段 street 和 city 放到 PurchaseOrder 类中,然后使用复合主键创建异常和 PuchaseOrder 表。但是在保存采购订单时,它给了我以下异常,错误:“城市”列不能为空。请参阅编辑问题部分,了解我这次如何保存采购订单。

以上是关于在休眠中使用复合键的主要内容,如果未能解决你的问题,请参考以下文章

如何使用注释创建休眠复合键

使用复合键(长,日期)选择最新的对象的休眠查询

没有复合键的休眠中的多对多

休眠 - 使用包含父 ID 的复合键 - OneToMany

休眠仅保存具有复合主键中的父外键的子表条目

休眠。符合。在联结表中设置复合主键