網頁

2018/7/23

Hibernate JPA One To Many / Many To One 主表為複合鍵(Compound Key)設定

Hibernate JPA OneToMany/ManyToOne複合鍵(Compound Key)設定如下。

本篇範例複合鍵分別在主表及子表,重點是要說明子表參考主表複合主鍵的設定方式。

例如有三個資料表分別為Customer(顧客),Order(訂單)及OrderDetail(訂單明細)關係如下。也就是一個顧客會有多筆訂單,而每一筆訂單又會有多筆明細。(OrderDetail又稱為OrderLine,代表的是一張訂單中的每一筆購買項目。)

+--------------+           +-----------------+           +-----------------+
|   Customer   |           |      Order      |           |    OrderDetail  |
+--------------+1         *+-----------------+1         *+-----------------+
|PK|CustomerId +-----------+FK|PK|CustomerId +-----------+FK|PK|CustomerId |
|  |           |           |  |PK|OrderNo    |           |FK|PK|OrderNo    |
+--+-----------+           +-----------------+           |  |PK|ListNo     |
                                                         +-----------------+

Customer的主鍵為CustomerId(顧客編號)。而CustomerId被Order參考為外鍵。

Order的主鍵為CustomerId及OrderNo(訂單編號)組成的複合主鍵。CustomerId為外鍵,參考於Customer的主鍵。

OrderDetail的主鍵為CustomerId,OrderNo及ListNo(項目編號)組成的複合主鍵。CustomerId及OrderNo為外鍵,參考於Order的複合主鍵。

則Hibernate JPA的Entiy設定如下。

Customer.java

@Entity
@Table(name="Customer")
public class Customer {

    @Id
    @Column(name="CustomerId")
    private Integer customerId;
    
    @OneToMany(mappedBy="customer")
    private List<Order> orderList;

    // getter and setter ommitted
}

Order.java
OrderPK.java

@Entity
@Table(name="Order")
public class Order {

    @EmbeddedId
    private OrderPK orderPk;
    
    @OneToMany(mappedBy="orderDetailPk.order")
    private List<OrderDetail> orderDetailList;
    
    // getter and setter ommitted
}

@Embeddable
public class OrderPK implements Serializable {

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="CustomerId")
    private Customer customer;
    
    @Column(name="OrderNo")
    private Integer orderNo;

    // getter and setter ommitted
}

OrderDetail.java
OrderDetailPK.java

@Entity
@Table(name="OrderDetail")
public class OrderDetail {

    @EmbeddedId
    private OrderDetailPK orderDetailPk;
    
    // getter and setter ommitted
}

@Embeddable
public class OrderDetailPK implements Serializable {

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumns({
        @JoinColumn(name="CustomerId", referencedColumnName="CustomerId"),
        @JoinColumn(name="OrderNo", referencedColumnName="OrderNo")
    })
    private Order order;
    
    @Column(name="ListrNo")
    private Integer listNo;

    // getter and setter ommitted
}

重點在於OrderDetailPK中ManyToOne的設定,因為參考的對象Order的主鍵為多欄位組成的複合主鍵,所以要用@JoinColumns設定多個@JoinColumn來達成複合主鍵的mapping設定。

當使用@JoinColumns時,@JoinColumn必須設定referencedColumnName屬性來指明要參考的Parent欄位名稱,否則若欄位資料型態皆相同,則INSERT時可能發生插入的欄位順序錯誤的情況。

如果本篇有幫助到您,幫忙點一下廣告支持,感恩。

引述API

Defines mapping for composite foreign keys. This annotation groups JoinColumn annotations for the same relationship. When the JoinColumns annotation is used, both the name and the referencedColumnName elements must be specified in each such JoinColumn annotation.


參考:

沒有留言:

張貼留言