幾種映射關係,但是有點亂,這裏來小結一下。關鍵是表之間如何產生映射關係,以及產生的表的結構。
1、一對一映射:
一對一是通過one-to-one標籤來產生映射關係的,其實,如果單單說是建立兩個表之間的關聯,只要在一個映射文件中配置one-to-one標籤就可以了,在另一個映射文件中,也做類似的配置,只會起到關聯的作用,建立起雙向的關聯。這裏舉Person和IdCard的例子,IdCard類的映射文件如下:
- <class name="IdCard" table="id_card">
- <id name="id">
- <generator class="native"></generator>
- </id>
- <property name="No"/>
- <one-to-one name="person" constrained="true"/>
- </class>
建立表的ddl語句如下:
- CREATE TABLE `id_card` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `No` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `FK627C1FB4AEED3EC` (`id`),
- CONSTRAINT `FK627C1FB4AEED3EC` FOREIGN KEY (`id`) REFERENCES `person` (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=gbk
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>就可以了的,看下面這個配置“一”角色的例子:
- 部門類的映射文件:
- <class name="Department">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <set name="emps">
- <key column="depart_id"/><!-- key指明瞭員工表中的外鍵,column爲這外鍵重命名列名-->
- <one-to-many class="Employee"/><!-- one-to-many指明瞭和哪個類進行一對多的映射 -->
- </set>
- </class>
- 員工類的映射文件:
- <class name="Employee">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <many-to-one name="depart" column="depart_id"></many-to-one>
- <!-- many-to-one指明瞭外鍵 ,會根據反射機制,找到要和Employee建立多對一關係的類-->
- </class>
- CREATE TABLE `employee` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(255) DEFAULT NULL,
- `depart_id` int(11) DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `FK4AFD4ACE972E0614` (`depart_id`),
- CONSTRAINT `FK4AFD4ACE972E0614` FOREIGN KEY (`depart_id`) REFERENCES `department` (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=gbk
3、多對多映射:
因爲是多對多的關係,只用兩個表是無法表示這種關係的,所以建立出來第三方表,只保存這兩個表之間的關係,這樣就把多對多映射轉換成了兩個多對一映射。如果單單是建立兩個表之間的關聯,和上兩種情況一樣,只需要在其中一個映射文件中配置即可,但是要建立雙向映射的話,就要在兩個映射文件中都配置關聯了。
這裏我們舉老師和學生的例子,他們的映射文件分別如下:
- <class name="Teacher">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <set name="students" table="teacher_student">
- <key column="teacher_id"/>
- <many-to-many class="Student" column="student_id"/>
- </set>
- </class>
- <class name="Student">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <set name="teachers" table="teacher_student">
- <key column="student_id"/>
- <many-to-many class="Teacher" column="teacher_id"/>
- </set>
- </class>
- CREATE TABLE `teacher_student` (
- `teacher_id` int(11) NOT NULL,
- `student_id` int(11) NOT NULL,
- PRIMARY KEY (`student_id`,`teacher_id`),
- KEY `FK2E2EF2DEDE6A927E` (`teacher_id`),
- KEY `FK2E2EF2DECDCF47DE` (`student_id`),
- CONSTRAINT `FK2E2EF2DECDCF47DE` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`),
- CONSTRAINT `FK2E2EF2DEDE6A927E` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`)
- ) 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操作上的連鎖反應