hibernate 映射 多對一

一對多和上文講的多對一兩種映射關係,其實就是站在相反的角度考慮一樣的事情。

一對多和多對一映射原理是同樣的,都在多的一端加入一個外鍵指向一的一端。也就是說,在關係數據庫的表中,他們的表及表字段都是同樣的。

他們的不一樣在於維護的關係:

          多對一維護的關係——多指向一的關係,若是維護了多指向一的關係,那麼加載多的時候會把一加載上來。

         一對多維護的關係——一指向多的關係,若是維護了一指向多的關係,那麼加載多的時候,會把一加載上來。

如今假如要用一對多映射描述學生和班級的關係。
一、hibernate單向一對多關聯映射(Classes----->Student)
實體Classes。一對多關係,加載時須要在一的一端(classes端)加載上來多的一端(Student),因此實體Classes中需包含實體Student的引用。

[java] view plaincopyprint?
01.package com.lzq.hibernate;  
02.import java.util.Set;  
03.public class Classes {  
04.    private int id;  
05.    private String name;  
06.    private Set student;  
07.    此處省略getter和setter方法  
08.}     

實體Student

[java] view plaincopyprint?
01.package com.lzq.hibernate;  
02.public class Student {  
03.    private int id;  
04.    private String name;  
05.    此處省略getter和setter方法  
06.}  
映射文件Classes.hbm.xml。一對多關係中,須要在多的一端維護關係,因此在Classes端加入「one-to-many」標籤維護關係。
[html] view plaincopyprint?
01.<?xml version="1.0"?>  
02.<!DOCTYPE hibernate-mapping PUBLIC   
03.    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
04.    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
05.<hibernate-mapping>  
06.    <class name="com.lzq.hibernate.Classes" table="t_classes">  
07.        <id name="id">  
08.            <generator class="native" />  
09.        </id>  
10.        <property name="name" />  
11.                <!-- 集合映射set-->  
12.                <set name="student">  
13.                        <!-- 設置classesid外鍵爲非空字段-->  
14.                        <key column="classesid" not-null="true"/>  
15.            <one-to-many class="com.lzq.hibernate.Student"/>  
16.        </set>  
17.    </class>  
18.</hibernate-mapping>  

映射文件Student.hbm.xml

[html] view plaincopyprint?
01.<?xml version="1.0"?>  
02.<!DOCTYPE hibernate-mapping PUBLIC   
03.    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
04.    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
05.<hibernate-mapping>  
06.    <class name="com.lzq.hibernate.Student" table="t_student">  
07.        <id name="id">  
08.            <generator class="native" />  
09.        </id>  
10.        <property name="name" />  
11.    </class>  
12.</hibernate-mapping>  

儘管咱們完成映射,可是這樣映射還存在必定的問題,看下面的加載:

[java] view plaincopyprint?
01.public void testOne2ManyAdd() throws Exception {  
02.        Session session=null;  
03.        Transaction tx=null;  
04.        try {  
05.            session=HibernateUtils.getSession();  
06.            tx=session.beginTransaction();  
07.            Student student1=new Student();  
08.            student1.setName("張三");  
09.            session.save(student1);  
10.            Classes classes=new Classes();  
11.            classes.setName("提升班");  
12.            Set students=new HashSet();  
13.            students.add(student1);  
14.            classes.setStudent(students);  
15.            session.save(classes);  
16.            tx.commit();  
17.        } catch (Exception e) {  
18.            e.printStackTrace();  
19.            HibernateUtils.closeSession(session);  
20.        }  
21.    }  

結果會拋PropertyValueException異常。緣由很簡單:咱們在多的一端(Student)沒有維護關係,也就是說,Student不知道本身是哪個班的,因此咱們在保存Student的時候關係字段classesid爲null。這就限制了外鍵必須爲容許非空,若是外鍵設置爲「不能爲空」,則沒法進行保存。而咱們這裏對外鍵設置,因此纔會拋出此異常。
那怎麼解決該問題呢?固然,咱們能夠在Classes.hbm.xml配置中去掉「 not-null='true' 」,這樣也能夠保存,可是咱們能夠觀察生成的SQL語句,此時進行了一條insert和update語句,顯然,它實現插入了student信息,而後在更新的classesid字段。這種方式顯然不友善。那麼除了這種方式,還能不能用別的方式解決?

這應爲此問題,才產生了雙向的一對多的關聯映射:

二、hibernate雙向一對多關聯映射(Classes<----->Student)

既然是雙向一對多關聯映射,那麼必定要在多的一端(Student)加入一的一端(Classes)的引用,這樣才能在多的一端(Student)進行存儲和加載。

[java] view plaincopyprint?
01.package com.lzq.hibernate;  
02.public class Student {  
03.    private int id;  
04.    private String name;  
05.      
06.    private Classes classes;  
07.    此處省略getter/setter方法  
08.}  

對應配置更改:

[html] view plaincopyprint?
01.<?xml version="1.0"?>  
02.<!DOCTYPE hibernate-mapping PUBLIC   
03.    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
04.    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
05.<hibernate-mapping>  
06.    <class name="com.lzq.hibernate.Student" table="t_student">  
07.        <id name="id">  
08.            <generator class="native" />  
09.        </id>  
10.        <property name="name" />  
11.                <!-- 此處須要與classes端的配置的字段保持一致-->  
12.                <many-to-one name="classes" column="classesid" />  
13.    </class>  
14.</hibernate-mapping>  

此外,既然雙向一對多關聯映射的產生是爲了彌補單向一對多關聯映射的缺陷,那麼避免程序員編寫程序仍然在一的一端(Classes)加載,咱們能夠採用反轉技術,設置從Classes端加載失效:

[html] view plaincopyprint?
01.<?xml version="1.0"?>  
02.<!DOCTYPE hibernate-mapping PUBLIC   
03.    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
04.    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
05.<hibernate-mapping>  
06.    <class name="com.lzq.hibernate.Classes" table="t_classes">  
07.        <id name="id">  
08.            <generator class="native" />  
09.        </id>  
10.        <property name="name" />  
11.        <!--反轉:設置從Classes端加入數據失效-->  
12.        <set name="student" inverse="true">  
13.            <key column="classesid" />  
14.            <one-to-many class="com.lzq.hibernate.Student"/>  
15.        </set>  
16.    </class>  
17.</hibernate-mapping>  

爲何多對一關聯映射不存在單向一對多中的問題呢?若是你明白了上面所講的,這個問題將很好回答。在多對一關聯映射裏面,因爲關係是在多的一端進行維護的,加載的時候從多的一端進行加載,固然沒有問題。

總結一下:在多對一關聯映射中,若是用到,常常採用雙向的方式來完成映射,彌補單向加載時的問題。
View Code
相關文章
相關標籤/搜索