JPA 對象關係映射之關聯關係映射策略

Hibernate,JPA 對象關係映射之關聯關係映射策略

關聯關係映射

關聯關係映射,是映射關係中比較複雜的一種映射關係,總的說來有一對一、一對多和多對多幾種關係。細分起來他們又有單向和雙向之分。

王 漢敏, 軟件工程師, IBM

2013 年 6 月 17 日

  • expand內容

關聯關係映射

關聯關係映射,是映射關係中比較複雜的一種映射關係,總的說來有一對一、一對多和多對多幾種關係。細分起來他們又有單向和雙向之分。下面我們逐一介紹一下。

單向 OneToOne

單向一對一是關聯關係映射中最簡單的一種,簡單地說就是可以從關聯的一方去查詢另一方,卻不能反向查詢。我們用下面的例子來舉例說明,清單 1 中的 Person 實體類和清單 2 中的 Address 類就是這種單向的一對一關係,我們可以查詢一個 Person 的對應的 Address 的內容,但是我們卻不能由一個 Address 的值去查詢這個值對應的 Person。

清單 1. 單向一對一關係的擁有端
 @Entity 
 public class Person implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String name; 
    private int age; 
    @OneToOne 
 private Address address; 

 //   Getters & Setters 
 }
清單 2. 單向一對一關係的反端
 @Entity 
 public class Address implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String street; 
    private String city; 
 private String country; 
 // Gettes& Setters 
 }
圖 1. 單向一對一關係對應的 ER 圖
Figure 1. 單向一對一關係對應的 ER 圖

從圖 1 他們的 ER 圖上可以看出,這種單向的一對一關係在數據庫中是以外鍵的形式被映射的。其中關係的發出端存儲一個指向關係的接收端的一個外鍵。在這個例子中 Person 表中的 ADDRESS_ID 就是指向 address 標的一個外鍵,缺省情況下這個外鍵的字段名稱,是以它指向的表的名稱加下劃線“_”加“ID”組成的。當然我們也可以根據我們的喜好來修改這個字段,修改的辦法就是使用 @JoinColumn 這個註解。在這個例子中我們可以將這個註解註釋在 Person 類中的 Address 屬性上去。

雙向 OneToOne

雙向關係有一方爲關係的擁有端,另一方是關係的反端,也就是“Inverse”端。在這裏例子中 Person 擁有這個關係,而 Address 就是關係的“Inverse”端。Address 中我們定義了一個 person 屬性,在這個屬性上我們使用了 @OneToOne 註解並且定義了他的“mappedBy”屬性,這個在雙向關係的“Inverse”端是必需的,在下面將要介紹的雙向關係中也要用到這個屬性。

清單 3. 雙向一對一關係中的接受端
 @Entity 
 public class Address implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String street; 
    private String city; 
 private String country; 
 @OneToOne(mappedBy = "address") 
 private Person person; 
 // Gettes& Setters 

 }

單向 OneToMany

單向關係的一對多我們可以用清單 4 和清單 5 來說明。在關係的發出端 Person 中我們使用 OneToMany 這個註解對 cellPhones 這個屬性進行了註釋,cellPhones 中存儲的是 CellPhone 的一個 List 對象,JPA 就是用這種方式實現一對多的。

清單 4. 單向一對多關係的發出端
 public class Person implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String name; 
    private int age; 
    @OneToMany 
    private List<CellPhone> cellPhones; 
    // Getters and Setters 
 }
清單 5. 單向一對多關係的接收端
 @Entity 
 public class CellPhone implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String manufacture; 
    private String color; 
    private Long  phoneNo; 
    // Getters and Setters 
 }
圖 2. 單向一對多關係對應的 ER 圖
Figure 2. 單向一對多關係對應的 ER 圖

在一對多關聯關係映射中,默認是以中間表的方式來映射這種關係的。如在本例中,中間表爲 person_cellphone,表的名稱爲關係的擁有端和 Inverse 端中間用下劃線連接。中間表的字兩個字段分別爲兩張表的得表名加下劃線“_”加 ID 組成。當然我們也可以改表這種默認的中間表的映射方式,我們可以在關係的擁有端使用 @JoinClolum 來使用外鍵的方式映射這個關係。

雙向 OneToMany

清單 6. 雙向一對多關係的接受端
 @Entity 
 public class Person implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String name; 
    private int age; 
  
    @OneToMany(mappedBy = "person") 
    private List<CellPhone> cellPhones; 
    // Getters and Setters 
 }
清單 7. 雙向一對多關係的發出端
 @Entity 
 public class CellPhone implements Serializable { 

    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    
    private String manufacture; 
    private String color; 
    private Long  phoneNo; 
    @ManyToOne 
    private Person person; 
    // Getters and Setters 
 }
圖 3. 雙向一對多關係對應的 ER 圖
Figure 3. 雙向一對多關係對應的 ER 圖

單向 ManyToMany

多對多關聯關係中只能通過中間表的方式進行映射。本例的單向多對多關係如下所示。

在清單 8 中我們使用了 ManyToMany 這個註解來對 Teacher 中的 Students 進行註釋,其中 Teacher 就是關係的發出端。而在 Student 中我們並沒有作任何定義,這是單向多對多的所要求的。

清單 8. 單向多對多關係的發出端
 @Entity 
 public class Teacher implements Serializable { 
   
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String name; 
    private Boolean gender; 
    private int age; 
    private int height; 
    @ManyToMany 
 private List<Student> students; 
 // Getters  and  Setters 
 }
清單 9. 單向多對多關係的反端
 @Entity 
 public class Student implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String name; 
    private Boolean gender; 
    private int age; 
    private int height; 
   //Getters  and  Setters 
 }
圖 4. Teacher 對應得數據庫表
Figure 4. Teacher 對應得數據庫表
圖 5. Students 對應得數據庫表
Figure 5. Students 對應得數據庫表
圖 6. 中間生成表
Figure 6. 中間生成表

雙向 ManyToMany

清單 10. 雙向多對多關係的擁有端
 @Entity 
 public class Teacher implements Serializable { 
   
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String name; 
    private Boolean gender; 
    private int age; 
    private int height; 
    @ManyToMany 
 private List<Student> students; 
 // Getters  and  Setters 
 }
清單 11. 雙向多對多關係的反端
 @Entity 
 public class Student implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String name; 
    private Boolean gender; 
    private int age; 
    private int height; 
    @ManyToMany(mappedBy = "students") 
    private List<Teacher> teachers; 
    //Getters  and  Setters 
 }
圖 7. 雙向多對多關係對應的 ER 圖
Figure 7. 雙向多對多關係對應的 ER 圖

總結

關聯關係映射,是對象映射關係中相對複雜的一種,但也是用處最多的一種,因爲數據中的表不可能都是單獨存在,彼此之間必定存在千絲萬縷的聯繫,這也是關係型數據庫的特徵所在。同樣關聯關係的映射,也是對象關係映射中的難點,重點,仔細揣摩,也還是很容易理解掌握的
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章