hibernate——一對一、多對一和多對多關係的比較

幾種映射關係,但是有點亂,這裏來小結一下。關鍵是表之間如何產生映射關係,以及產生的表的結構。

1、一對一映射:

一對一是通過one-to-one標籤來產生映射關係的,其實,如果單單說是建立兩個表之間的關聯,只要在一個映射文件中配置one-to-one標籤就可以了,在另一個映射文件中,也做類似的配置,只會起到關聯的作用,建立起雙向的關聯。這裏舉Person和IdCard的例子,IdCard類的映射文件如下:

[html] view plaincopy
  1. <class name="IdCard" table="id_card">  
  2.         <id name="id">  
  3.               <generator class="native"></generator>  
  4.         </id>  
  5.         <property name="No"/>  
  6.         <one-to-one name="person" constrained="true"/>  
  7. </class>  
constrained="true"指定了將person表的主鍵設置爲id_card表的外鍵,這樣就建立起了兩個表的關聯,若不指定,兩個表就是孤立的,互相沒有關係。

建立表的ddl語句如下:

  1. CREATE TABLE `id_card` (  
  2.   `id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `Novarchar(255) DEFAULT NULL,  
  4.   PRIMARY KEY (`id`),  
  5.   KEY `FK627C1FB4AEED3EC` (`id`),  
  6.   CONSTRAINT `FK627C1FB4AEED3EC` FOREIGN KEY (`id`) REFERENCES `person` (`id`)  
  7. ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=gbk  
在Person類的映射文件中可以不指定one-to-one標籤,但那樣建立起來的是單向的映射關係,即從id_card表可以映射到person表,但是反之就不行。這在通過person表查詢id_card表時,不能查詢。如果要讓person關聯到id_card那麼就要在Person類的映射文件中,也配置一下one-to-one標籤了。


onstrained默認值爲false

constrained只能在one-to-one的映射中使用,(一般在主表的映射中,有外鍵的那個表)。如果constrained=true,則表明存在外鍵與關聯表對應,並且關聯表中肯定存在對應的鍵與其對應, 另外該選項最關鍵的是影響save和delete的先後順序。例如增加的時候,如果constainted=true,則會先增加關聯表,然後增加本表。刪除的時候反之。

one-to-one的單向關聯中,如果constrained=false,則會在查詢時就全部取出來,用left outer join的方式。如果constrained=true,hibernate即會延遲加載sql,只把主表的查出來,等有用到關聯表的再發sql取。

one-to-one的雙向關聯中,必須設置constrained=true,要不然會有重複數據讀,如2個表user,car;在位false時sql如下:select * from user a left outer join car b on a.id=b.id left outer join on user c on a.id=c.id where a.id=? 刪除的時候最好刪除從表,刪除主表會先查詢下主表,在聯合查詢下。



2、多對一映射:

建立兩個表的映射的關係,都是通過建立外鍵來關聯的,多對一也不例外,例如員工和部門的關係屬於多對一的關係,多個員工屬於同一個部門,所以在部門類中要有一個員工的集合屬性。要實現雙向映射的話,還必須在員工類中有部門的屬性。如果單單建立兩個表之間的關聯,也像一對一一樣,只需要在一個映射文件中配置就可以了,但是,多對一的映射文件的配置不像一對一那樣簡單,相對複雜的是在“一”這個角色,不是隻使用一個<one-to-many>就可以了的,看下面這個配置“一”角色的例子:

[html] view plaincopy
  1. 部門類的映射文件:  
  2. <class name="Department">  
  3.         <id name="id">  
  4.             <generator class="native"/>  
  5.         </id>  
  6.         <property name="name"/>  
  7.           
  8.         <set name="emps">  
  9.             <key column="depart_id"/><!-- key指明瞭員工表中的外鍵,column爲這外鍵重命名列名-->  
  10.             <one-to-many class="Employee"/><!-- one-to-many指明瞭和哪個類進行一對多的映射 -->  
  11.         </set>  
  12. </class>  
它是配置了一個set標籤,在標籤中指定了要關聯的類和在要關聯類中的外鍵。“一”這一方是通過這種方式建立和“多”的關聯的。那麼,要是用“多”那一方怎麼建立關聯呢?看下例:

[html] view plaincopy
  1. 員工類的映射文件:  
  2. <class name="Employee">  
  3.         <id name="id">  
  4.             <generator class="native"/>  
  5.         </id>  
  6.         <property name="name"/>  
  7.         <many-to-one name="depart" column="depart_id"></many-to-one>  
  8.         <!-- many-to-one指明瞭外鍵 ,會根據反射機制,找到要和Employee建立多對一關係的類-->  
  9. </class>  
使用<many-to-one>標籤也可以建立起和部門表的關聯,而且這種方式要簡潔很多。不管用哪種方式建立關聯,所得的數據庫的結果是一樣的,如本例中,建立的員工表的ddl語句爲:

  1. CREATE TABLE `employee` (  
  2.   `id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `namevarchar(255) DEFAULT NULL,  
  4.   `depart_id` int(11) DEFAULT NULL,  
  5.   PRIMARY KEY (`id`),  
  6.   KEY `FK4AFD4ACE972E0614` (`depart_id`),  
  7.   CONSTRAINT `FK4AFD4ACE972E0614` FOREIGN KEY (`depart_id`) REFERENCES `department` (`id`)  
  8. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=gbk  


3、多對多映射:

因爲是多對多的關係,只用兩個表是無法表示這種關係的,所以建立出來第三方表,只保存這兩個表之間的關係,這樣就把多對多映射轉換成了兩個多對一映射。如果單單是建立兩個表之間的關聯,和上兩種情況一樣,只需要在其中一個映射文件中配置即可,但是要建立雙向映射的話,就要在兩個映射文件中都配置關聯了。

這裏我們舉老師和學生的例子,他們的映射文件分別如下:

[html] view plaincopy
  1. <class name="Teacher">  
  2.         <id name="id">  
  3.             <generator class="native"/>  
  4.         </id>  
  5.         <property name="name"/>  
  6.         <set name="students" table="teacher_student">  
  7.             <key column="teacher_id"/>  
  8.             <many-to-many class="Student" column="student_id"/>  
  9.         </set>  
  10. </class>  
[html] view plaincopy
  1. <class name="Student">  
  2.         <id name="id">  
  3.             <generator class="native"/>  
  4.         </id>  
  5.         <property name="name"/>  
  6.         <set name="teachers" table="teacher_student">  
  7.             <key column="student_id"/>  
  8.             <many-to-many class="Teacher" column="teacher_id"/>  
  9.         </set>  
  10. </class>  
是不是看起來和多對一的映射文件有些類似?但是,不同的是,這裏出現了第三個表:teacher_student,表中只有兩列:teacher_id和student_id,並且分別是teacher和student表的外鍵,建立的teacher_student表就是老師和學生表之間的關聯,其建立的ddl語句爲:

  1. CREATE TABLE `teacher_student` (  
  2.   `teacher_id` int(11) NOT NULL,  
  3.   `student_id` int(11) NOT NULL,  
  4.   PRIMARY KEY (`student_id`,`teacher_id`),  
  5.   KEY `FK2E2EF2DEDE6A927E` (`teacher_id`),  
  6.   KEY `FK2E2EF2DECDCF47DE` (`student_id`),  
  7.   CONSTRAINT `FK2E2EF2DECDCF47DE` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`),  
  8.   CONSTRAINT `FK2E2EF2DEDE6A927E` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`)  
  9. ) ENGINE=InnoDB DEFAULT CHARSET=gbk  


通過上面的總結,應該清楚以下幾個問題:

1、如果說單單建立兩個表之間的關聯,在其中一個映射文件中配置關聯就可以了,就能夠在數據庫中生成外鍵,建立關聯。

2、雖說在一個映射文件中就可以建立兩個表的關聯,但是不同的映射關係在不同的映射文件中,配置的方法是不同的。

3、若要建立雙向的關聯的話,就要在兩個映射文件中都進行關聯配置。



進一步分析‘1 to N’ 和 ‘N to 1’ 之間的關聯


hihernate一對多關聯映射 , 單向 Employee -----> Department: 
多對一關聯映射:在'N'的一端加入一個外鍵指向'1'的一端,它維護的關係是多指向一
一對多關聯映射:在'N'的一端加入一個外鍵指向'1'的一端,它維護的關係是一指向多
也就是說一對多和多對一的映射策略是一樣的,只是站的角度不同




hihernate一對多關聯映射,  雙向 Employee <----->Department: 
一對多雙向關聯映射:
 * 在一一端的集合上使用<key>,在對方表中加入一個外鍵指向'1'端
 * 在'N'一端採用<many-to-one>
 
注意:<key>標籤指定的外鍵字段必須和<many-to-one>指定的外鍵字段一致,否則引用字段的錯誤
 
如果在'1'端維護一對多關聯關係,hibernate會發出多餘的udpate語句,所以我們一般在'N'的一端來維護關聯關係
關於inverse屬性:
 inverse主要用在一對多和多對多雙向關聯上,inverse可以被設置到集合標籤<set>上,
 默認inverse爲false,所以我們可以從'1'一端和'N'一端維護關聯關係,
 如果設置成inverse爲true,則我們只能從'N'一端來維護關聯關係
  
inverse和cascade
 * inverse是關聯關係的控制方向
 * cascade操作上的連鎖反應


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章