7.映射(3)(一對多)(hibernate筆記)

其實和多對一本質上是一樣的,也是在many的一方加一個字段作為外鍵,指向one的一方的主鍵,只是加載的時候不一樣。多對一的時候我們加載many的一方可以將one的一方加載出來,但是一對多的時候是加載one的一方可以將many的一方加載出來。

一、單向一對多(工程hibernate_one2many_1

這里我們給出一個班級對應多個學生的例子。
相關映射:

實體類映射.png

數(shù)據(jù)庫表映射.JPG

注意:這里在實體類中是在one的一方維護了一個集合,但是在數(shù)據(jù)庫中是在many的一方維護了一個指向one主鍵的外鍵。

Student.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.itcast.hibernate.Student" table="_student">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
    </class>
</hibernate-mapping>

Classes.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.hibernate">
    <class name="Classes" table="_classes">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <set name="students">
            <key column="classesid"></key>
            <one-to-many class="Student"/>
        </set>
    </class>
</hibernate-mapping>

測試:
One2ManyTest.java

package cn.itcast.hibernate;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.hibernate.Session;
import org.junit.Test;

public class One2ManyTest {
    
    @Test
    public void testSave1(){
        Session session = null;
        try{
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Student student1 = new Student();
            student1.setName("張三");
            session.save(student1);
            
            Student student2 = new Student();
            student2.setName("李四");
            session.save(student2);
            
            Set students = new HashSet();
            students.add(student1);
            students.add(student2);
            Classes classes = new Classes();
            classes.setName("高一班");
            classes.setStudents(students);
            
            session.save(classes);
            session.getTransaction().commit();
            
        }catch(Exception e){
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
    
    @Test
    public void testLoad1(){
        Session session = null;
        try{
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Classes classes = (Classes) session.load(Classes.class, 1);
            System.out.println("classes.name = " + classes.getName());
            Set students = classes.getStudents();
            for(Iterator iterator = students.iterator(); iterator.hasNext();){
                Student student = (Student) iterator.next();
                System.out.println("student.name = " + student.getName());
            }
            session.getTransaction().commit();
            
        }catch(Exception e){
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
}

說明:

  • 對于save方法我們可以看到發(fā)出sql語句的順序是:
Hibernate: insert into _student (name) values (?)
Hibernate: insert into _student (name) values (?)
Hibernate: insert into _classes (name) values (?)
Hibernate: update _student set classesid=? where id=?
Hibernate: update _student set classesid=? where id=?

可以發(fā)現(xiàn)在存儲many一方的時候沒有設置其classid,在之后保存one一方之后再對many一方進行更新。

  • 對于load方法我們看到其發(fā)出sql語句的順序是:
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from _classes classes0_ where classes0_.id=?
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_ from _student students0_ where students0_.classesid=?

也就是說我們可以通過one的一方查出many的一方信息,但是不能反過來。

雙向一對多(工程hibernate_one2many_2

相關映射:

實體類映射.png
數(shù)據(jù)庫表映射.JPG

說明:雙向映射只需要在Student類中加上一個private Classes classes字段,存儲的時候還是和以前一樣。

Student.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.itcast.hibernate.Student" table="_student">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <many-to-one name="classes" column="classesid"></many-to-one>
    </class>
</hibernate-mapping>

說明:對于one的一方相關實體類和配置文件不變,但是對于many一方我們需要在其實體類中加入一個屬性,而在其配置文件中我們也需要對這一屬性進行配置。由于在數(shù)據(jù)庫中one對應的表中的外鍵字段只有classid,所以在兩個配置文件中這一字段必須名字一樣。

測試:
One2ManyTest.java

package cn.itcast.hibernate;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.junit.Test;

public class One2ManyTest {

    @Test
    public void testSave1(){
        Session session = null;
        try{
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Student student1 = new Student();
            student1.setName("張三");
            session.save(student1);
            
            Student student2 = new Student();
            student2.setName("李四");
            session.save(student2);
            
            Set students = new HashSet();
            students.add(student1);//這表示在one的一方維護關系
            students.add(student2);
            Classes classes = new Classes();
            classes.setName("高一班");
            classes.setStudents(students);
            
            session.save(classes);
            session.getTransaction().commit();
            
        }catch(Exception e){
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }

    @Test
    public void testSave2(){
        Session session = null;
        try{
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Classes classes = new Classes();
            classes.setName("高一班");
            session.save(classes);
            
            Student student1 = new Student();
            student1.setName("張三");
            student1.setClasses(classes);//這表示在many的一方維護關系
            session.save(student1);
            
            Student student2 = new Student();
            student2.setName("李四");
            student2.setClasses(classes);
            session.save(student2);
            
            session.getTransaction().commit();
            
        }catch(Exception e){
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
}

說明

  • 對于testSave1方法和之前的例子一樣,但是這種方式有個缺點,當classid不能為null的時候會出現(xiàn)異常,所以我們一般不采用這種方式。因為這種方式是在one的一方維護映射關系。

  • 我們也可以先存儲one的一方,如方法testSave2方法所示。發(fā)出sql語句的順序是:

Hibernate: insert into _classes (name) values (?)
Hibernate: insert into _student (name, classesid) values (?, ?)
Hibernate: insert into _student (name, classesid) values (?, ?)

這比第一種方式要簡便。因為在存儲many一方的時候就已經(jīng)知道其映射關系了,即在many一方維護關系。

  • 由于我們一般不推薦在one的一方維護關系,所以我們一般讓one這邊維護關系的功能失效,此時Classes.hbm.xml為:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.hibernate">
    <class name="Classes" table="_classes">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <set name="students" inverse="true" cascade="all">
            <key column="classesid"></key>
            <one-to-many class="Student"/>
        </set>
    </class>
</hibernate-mapping>

此時我們再使用方法testSave1進行存儲同樣是可以進行存儲的,但是卻不會存儲映射關系,即classid為null,這是因為one的一方已經(jīng)不具備維護關系的功能了。

  • inverse主要用在一對多和多對多雙向關聯(lián)上,inverse可以被設置到集合標簽<set>上,默認inverse為false,所以我們可以從”one“一端和”many“一端維護關聯(lián)關系,如果設置成inverse為true,則我們只能從many一端來維護關聯(lián)關系。注意:inverse屬性,只影響數(shù)據(jù)的存儲,也就是持久化

當然此時我們也可以對方法testSave1進行改進:

    @Test
    public void testSave3(){
        Session session = null;
        try{
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Classes classes = new Classes();
            classes.setName("高一班");
            
            
            Student student1 = new Student();
            student1.setName("張三");
            student1.setClasses(classes);

            
            Student student2 = new Student();
            student2.setName("李四");
            student2.setClasses(classes);
            
            Set students = new HashSet();
            students.add(student1);
            students.add(student2);
            
            classes.setStudents(students);
            
            session.getTransaction().commit();
            
        }catch(Exception e){
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }

說明:可以看到我們在保存many之前就已經(jīng)將其classid設置好了,這樣就可以存儲了,雖然one的一方同樣沒有維護關系。

對于加載方法:

    @Test
    public void testLoad1(){
        Session session = null;
        try{
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Classes classes = (Classes) session.load(Classes.class, 1);
            System.out.println("classes.name = " + classes.getName());
            Set students = classes.getStudents();
            for(Iterator iterator = students.iterator(); iterator.hasNext();){
                Student student = (Student) iterator.next();
                System.out.println("student.name = " + student.getName());
            }
            session.getTransaction().commit();
            
        }catch(Exception e){
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
    
    @Test
    public void testLoad2(){
        Session session = null;
        try{
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Student student = (Student) session.load(Student.class, 1);
            System.out.println("student.name = " + student.getName());
            System.out.println("student.classes.name = " + student.getClasses().getName());
            session.getTransaction().commit();
            
        }catch(Exception e){
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }

說明:可以看到對于雙向關聯(lián)顯然可以雙向查詢。

最后:我們一般在many一方維護關系,因為維護關系的字段就在many這邊,所以盡量在many一方維護關系,同時將one這邊維護關系的功能取消掉。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 一. Java基礎部分.................................................
    wy_sure閱讀 4,011評論 0 11
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內(nèi)部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,671評論 18 399
  • 再開始本次知識點之前,我們先來思考下get與load的區(qū)別。 對于Hibernate get方法,Hibernat...
    FTOLsXD閱讀 407評論 0 1
  • 集合映射 開發(fā)流程:需求分析/數(shù)據(jù)庫設計、項目設計/ 編碼/測試/實施部署上線/驗收 需求 : 用戶購買, 填寫地...
    奮斗的老王閱讀 966評論 0 51
  • 【連載】愿得一心人,白頭不相離-目錄 上一篇 接續(xù) 卓王孫備齊所需,邀司馬相如入席。司馬相如起身向琴位走去,我這才...
    瀟然灬閱讀 458評論 6 7

友情鏈接更多精彩內(nèi)容