posts - 89,  comments - 98,  trackbacks - 0
          在前一篇文章《使用Hibernate來實現持久對象》中,介紹了Hibernate的基本概念,然后用實例演示了怎么在Web應用中使用Hibernate來封裝持久數據對象。然而在現實的項目中,我們往往需要操作多個數據表,并且多個表之間往往存在復雜的關系,在本文,將介紹怎么在Hibernate中描述多個表的映射關系,并且演示怎么操作關系復雜的持久對象。

            本文的全部代碼在這里下載

            案例介紹

            在第一篇文章中,我們對一個表進行了簡單的封裝。在這篇文章中,我們討論更加復雜的情況。

            在這個例子中,將考慮到表之間的一對一、一對多、多對多的情況。如圖1所示。


          圖1 實體之間的映射關系

            在上面的數據模型圖中,Student是所有表的核心,它和Classes表是一對多的關系,和Course表是多對多的關系(通過Student_Course_Link表來鏈接),和Address表是一對一的關系。

            通過分析,我們可以把上面的數據模型轉換成如下的Java持久對象,如圖2所示。


          圖2 持久對象之間的關系

            可以看出,數據模型圖和Java持久對象的類圖有非常大的相似性,但是不完全相同。比如Classes表和Student表是一對多的關系;在類圖中,兩者仍然是一對多的關系,但是在Classes類中添加了一個student屬性,屬性的類型是java.util.Set,它表示Classes對象中包含的所有Student對象。

            創建Hibernate持久對象

            已經對數據模型經過了分析,現在就可以創建持久對象了。持久對象之間的關系由圖2所示的類圖指定。

            我們首先來看Student類,它是這個關系映射的核心,代碼如例程1所示。

            例程1 Student持久對象(Student.java)

          package com.hellking.study.hibernate;

          import java.util.Set;
          /**
          ?*在hibernate中代表了Students表的類。
          ?*/
          public class Student
          {
          ?? /**屬性,和students表中的字段對應**/
          ?? private String id;
          ?? private String name;
          ?? /**和其它類之間的映射關系**/
          ?? private Set courses;
          ?? private Classes classes;
          ?? private Address address;
          ??
          ?? ?/**屬性的訪問方法,必須是公共的方法**/
          ?? ?public void setId(String string) {
          ??id = string;
          ?}
          ?
          ?public String getId() {
          ??return id;
          ?}
          ?
          ?public void setName(String name)
          ?{
          ??this.name=name;
          ?}
          ?public String getName()
          ?{
          ??return this.name;
          ?}
          ?
          ?/**操作和其它對象之間的關系**/
          ?public void setCourses(Set co)
          ?{
          ??this.courses=co;
          ?}
          ?public Set getCourses()
          ?{
          ??return this.courses;
          ?}
          ?public void setAddress(Address ad)
          ?{
          ??this.address=address;
          ?}
          ?public Address getAddress()
          ?{
          ??return this.address;
          ?}
          ?public void setClasses(Classes c)
          ?{
          ??this.classes=c;
          ?}
          ?public Classes getClasses()
          ?{
          ??return this.classes;
          ?}??
          }

            在Student類中,由于Students表和Classes的表是多對一的關系,故它包含了一個類型為Classes的classes屬性,它的實際意義是一個學生可以有一個班級;Students表和Address的表是一對一的關系,同樣也包含了一個類型為Address的address屬性,它的實際意義是一個學生有一個地址;Students表和Course是多對多的關系,故它包含了一個類型為java.util.Set的course屬性,它的實際意義是一個學生可以學習多門課程,同樣,某個課程可以由多個學生來選修。

            Classes對象和Student對象是一對多的關系。Classes對象包含一個類型為java.util.Set的students屬性,它的代碼如例程2所示。

            例程2 Classes持久對象(Classes.java)

          package com.hellking.study.hibernate;

          import java.util.Set;
          /**
          ?*在hibernate中代表了Classes表的類。
          ?*/
          public class Classes
          {
          ?? /**屬性,和classes表的字段一致**/
          ?? private String id;?
          ?? private String name;
          ?? /**和其它類之間的映射關系**/
          ?? private Set students;
          ??
          ?? /**屬性的訪問方法,必須是公共的方法**/
          ?? public void setId(String string) {
          ??id = string;
          ?}
          ?
          ?public String getId() {
          ??return id;
          ?}
          ?
          ?public void setName(String name)
          ?{
          ??this.name=name;
          ?}
          ?public String getName()
          ?{
          ??return this.name;
          ?}
          ?
          ?/**操作和其它對象之間的關系**/
          ?public void setStudents(Set stud)
          ?{
          ??this.students=stud;
          ?}
          ?public Set getStudents()
          ?{
          ??return this.students;
          ?}
          }

            Course持久對象在前一篇文章已經介紹,在這里就不再列舉。Address持久對象比較簡單,除了表字段定義的屬性外,沒有引入其它的屬性,請參考本文的代碼。

            描述對象之間的關系

            現在我們已經編寫好了持久對象,下面的任務就是描述它們之間的關系。首先我們看Student持久對象的描述,如例程3所示。

            例程3 Student持久對象的描述(Student.hbm.xml)

          <?xml version="1.0"?>

          <!DOCTYPE hibernate-mapping PUBLIC
          ??? "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
          ??? "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

          <hibernate-mapping>
          ??? <class
          ??????? name="com.hellking.study.hibernate.Student"
          ??????? table="Students"
          ??????? dynamic-update="false"
          ??? >
          ?? <!-- 描述ID字段-->
          ??????? <id
          ??????????? name="id"
          ??????????? column="StudentId"
          ??????????? type="string"
          ??????????? unsaved-value="any"
          ??????? >
          ??????????? <generator class="assigned"/>
          ??????? </id>
          ???? <!-- 屬性-->
          ???????? <property
          ??????????? name="name"
          ??????????? type="string"
          ??????????? update="true"
          ??????????? insert="true"
          ??????????? column="Name"
          ??????? />
          <!-- 描述Student和Course多對多的關系-->
          ???????? <set
          ??????????? name="courses"
          ??????????? table="Student_Course_Link"
          ??????????? lazy="false"
          ??????????? inverse="false"
          ??????????? cascade="all"
          ??????????? sort="unsorted"
          ??????? >

          ????????????? <key
          ????????????????? column="StudentId"
          ????????????? />

          ????????????? <many-to-many
          ????????????????? class="com.hellking.study.hibernate.Course"
          ????????????????? column="CourseId"
          ????????????????? outer-join="auto"
          ????????????? />
          ??????? </set>
          <!-- 描述Student和Classes之間多對一的關系-->
          ????????? <many-to-one
          ??????????? name="classes"
          ??????????? class="com.hellking.study.hibernate.Classes"
          ??????????? cascade="none"
          ??????????? outer-join="auto"
          ??????????? update="true"
          ??????????? insert="true"
          ??????????? column="ClassesId"
          ??????? />
          ???????
          <!-- 描述Student和Address之間一對一的關系-->???????
          ?<one-to-one
          ??????????? name="address"
          ??????????? class="com.hellking.study.hibernate.Address"
          ??????????? cascade="none"
          ??????????? outer-join="auto"
          ??????????? constrained="false"
          ??????? />??????
          ??? </class>
          </hibernate-mapping>

            在Student.hbm.xml描述符中,共描述了三種關系。第一種是Student和Address之間一對一的關系,它是最簡單的關系,使用:

            <one-to-one name="" class="">

            來描述,這里的name表示的是Student對象中名稱為address的屬性;class表示的是address屬性的類型:com.hellking.study.hibernate.Address。

            接下來看Student和Classes之間多對一的關系,使用:

            <many-to-one?? name="classes" class="com.hellking.study.hibernate.Classes" column="ClassesId" …?? />

            來描述。同樣,name表示的是Student對象中名稱為classes的屬性;class表示的是classes屬性的類型,column表示Student表引用Classes表使用的外部鍵名稱。對應的,在Classes類中也引用了Student類,它使用了以下的描述符來描述這個關系:

          ??????? <set
          ??????????? name="students"
          ??????????? table="Students"
          ??????????? lazy="false"
          ??????????? inverse="false"
          ??????????? cascade="all"
          ??????????? sort="unsorted"
          ??????? >
          ????????????? <key
          ????????????????? column="ClassesId"
          ????????????? />

          ????????????? <one-to-many
          ????????????????? class="com.hellking.study.hibernate.Student"
          ????????????? />
          ??????? </set>

            在描述Student和Course之間多對多關系時,使用了以下的方法:

          ??????? <set
          ??????????? name="courses"
          ??????????? table="Student_Course_Link"
          ??????????? lazy="false"
          ??????????? inverse="false"
          ??????????? cascade="all"
          ??????????? sort="unsorted"
          ??????? >
          ????????????? <key
          ????????????????? column="StudentId"
          ????????????? />
          ????????????? <many-to-many
          ????????????????? class="com.hellking.study.hibernate.Course"
          ????????????????? column="CourseId"
          ????????????????? outer-join="auto"
          ????????????? />
          ??????? </set>

            在映射多對多關系時,需要另外使用一個鏈接表,這個表的名字由table屬性指定,鏈接表包含了兩個字段:CourseId和StudentId。以下的描述:

            <key column="StudentId">

            指定了Student對象在Student_Course_Link鏈接表中的外部鍵。對應的,在Course持久對象使用了以下的描述符來描述這個關系:

          ??????? <set
          ??????????? name="students"
          ??????????? table="Student_Course_Link"
          ??????????? lazy="false"
          ??????????? inverse="false"
          ??????????? cascade="all"
          ??????????? sort="unsorted"
          ??????? >
          ????????????? <key
          ????????????????? column="CourseId"
          ????????????? />

          ????????????? <many-to-many
          ????????????????? class="com.hellking.study.hibernate.Student"
          ????????????????? column="StudentId"
          ????????????????? outer-join="auto"
          ????????????? />
          ??????? </set>

            由于其它持久對象的描述基本一樣,在這里就不一一列舉了,請參考本文的源代碼。最后別忘了在hibernate.cfg.xml里增加這幾個對象的描述。

          ??????? <!-- Mapping files -->
          ??????? <mapping resource="Address.hbm.xml"/>
          ??????? <mapping resource="Student.hbm.xml"/>
          ??????? <mapping resource="Classes.hbm.xml"/>
          ??????? <mapping resource="Course.hbm.xml"/

            使用映射關系

            下面我們開發一個簡單的實例來測試這個映射。持久對象使用最頻繁的操作是增加數據、查詢數據、刪除數據、更新數據。對于更新數據的操作的情況,多個表的操作和單個表沒有兩樣,在這里不舉例了。

            添加數據到數據庫

            我們在這里測試前三種操作,首先來看添加數據到數據庫的情況,如例程4所示。

            例程4 測試持久對象之間的映射關系之添加數據(MapTestBean.java部分代碼)

          ??/**
          ? *在數據庫中添加數據
          ? */
          ? public void addData(String studentId,String classesId,String coursesId)
          ??????? throws HibernateException {
          ??????? try
          ??????? {
          ????????? /**
          ?????????? *以下的代碼添加了一個Student,同時為Student指定了
          ?????????? *Address、Courses和Classses。
          ?????????? */
          ????????? beginTransaction();?
          ????????? //創建一個Student對象 。??????
          ????????? Student student = new Student();
          ????????? student.setName("hellking2");
          ????????? student.setId(studentId);
          ?????????
          ????????? //創建一個Address對象。
          ????????? Address addr=new Address();
          ????????? addr.setCity("beijing");
          ????????? addr.setState("bj");
          ????????? addr.setStreet("tsinghua");
          ????????? addr.setZip("100083");
          ????????? addr.setId(student.getId());???????
          ???//設置Student和address的關系。
          ????????? student.setAddress(addr);??????
          ????????
          ???????? Set set=new HashSet();
          ???????? set.add(student);
          ???????? //創建一個course對象。
          ???????? Course course=new? Course? ();
          ???????? course.setId(coursesId);
          ???????? course.setName("computer_jsp");
          ???????? //設置course和student對象之間的關系。
          ???????? course.setStudents(set);
          ??????
          ???????? //創建一個classes對象。
          ???????? Classes cl=new Classes();
          ???????? cl.setId(classesId);
          ???????? cl.setName("engine power");
          ???????? //設置某個classes對象包含的students對象。
          ???????? cl.setStudents(set);
          ??????? //由于是雙向的關系,student對象也需要設置一次。
          ???????? student.setClasses(cl);???????
          ????????
          ???????? //保存創建的對象到session中。
          ???????? session.save(cl);
          ???????? session.save(course);
          ???????? session.save(student);
          ???????? session.save(addr);
          ???????? //提交事務,使更改生效。
          ???????? endTransaction(true);
          ?????? }
          ?????? catch(HibernateException e)
          ?????? {????????
          ?????????? System.out.println("在添加數據時出錯!");
          ?????????? e.printStackTrace();
          ?????? ??? throw e;
          ?????? }
          ??? }

            在例程4中,添加數據到數據庫之前,首先設置持久對象的各個屬性,如:

            student.setName("hellking2");

            這種設置屬性的方式和普通的類沒有什么區別,設置完所有的屬性后,就設置持久對象之間的關系,如:

            student.setAddress(addr);

            如果存在對象之間的多重關系,那么可能需要把對象保存在Set集合中,然后再進行設置,如:

            Set set=new HashSet();
            set.add(student);
            course.setStudents(set);

            當設置完所有的屬性和對象關系之后,就可以調用:

            session.save(persistentObject);

            方法把持久對象保存到Hibernate會話中。最后,調用endTransaction來提交事務,并且關閉Hibernate會話。

            數據查詢

            在復雜的實體對象映射中,往往查詢也比較復雜。作為演示,我們在這里也提供了幾個查詢方法,如例程5所示。

            例程5 測試持久對象之間的映射關系之查詢數據(MapTestBean.java部分代碼)

          ??? /**
          ???? *獲得某個給定studentid的Student的地址信息
          ???? */
          ??? public Address getAddress(String id) throws HibernateException
          ??? {??? ?
          ??? ???? beginTransaction();??? ?
          ???? ?Student st=(Student)session.load(Student.class,id);???
          ???? ?Address addr=(Address)session.load(Address.class,st.getId());
          ???? ?endTransaction(false);?
          ???return addr;
          ???
          ??? }
          ???
          ??? /**
          ???? *獲得某個給定studentid的Student的所有課程
          ???? */
          ??? public Set getCourses(String id)throws HibernateException
          ??? {
          ??? ?beginTransaction();??? ?
          ??? ?Student st=(Student)session.load(Student.class,id);
          ???? ?endTransaction(false);???
          ??? ?return st.getCourses();
          ??? }
          ???
          ??? /**
          ???? *測試獲得某個給定studentid的Student所屬的Classes
          ???? */
          ??? public Classes getClasses(String id)throws HibernateException
          ??? {??? ?
          ??? ?beginTransaction();??? ?
          ??? ?Student st=(Student)session.load(Student.class,id);
          ??? ?System.out.println(st.getClasses().getId());?
          ??? ?endTransaction(false);?
          ??? ?return st.getClasses();
          ??? }

            這里提供了三種查詢方法,分別是:

            查詢給定id的Student的Address信息;
            查詢給定id的Student的所有Courses信息;
            查詢給定id的Student所屬的Classes信息。

            在查詢時,首先使用beginTransaction()方法創建一個Hibernate會話對象,并且開始一個新Hibernate事務;然后通過session.load()方法獲得給定ID的Student對象,如:

            Student st=(Student)session.load(Student.class,id);

            最后調用student.getXXX()方法返回指定的對象。

            刪除數據

            在表的關系比較復雜時,要刪除數據,往往存在級聯刪除的情況,由于級聯刪除的情況比較復雜,在這里就不舉例了。假設我們要刪除和某個給定id的student對象的所有相關的記錄,就可以使用例程6所示的方法。

            例程6 測試持久對象之間的映射關系之刪除數據(MapTestBean.java部分代碼)

          ??? /**
          ???? *刪除和某個學生相關的所有信息
          ???? *(這里只是測試,我們暫且不說這種操作的意義何在)。
          ???? */
          ??? public void delteStudent(String id)throws HibernateException
          ??? {
          ??? ?beginTransaction();??? ?
          ??? ?Student st=(Student)session.load(Student.class,id);???? ?
          ??? ?Address addr=(Address)session.load(Address.class,st.getId());
          ??? ?//刪除address信息。
          ??? ?session.delete(addr);
          ??? ?//刪除classes信息。
          ??? ?session.delete(st.getClasses());
          ??? ?/**
          ??? ? *逐個刪除course。
          ??? ? */
          ??????? for(Iterator it=st.getCourses().iterator();it.hasNext();)
          ??????? {
          ??????? ?Course c=(Course)it.next();
          ??????? ?session.delete(c);
          ??????? }
          ??????? //最后,刪除student對象。
          ??? ?session.delete(st);
          ??? ?endTransaction(true);?
          ??? }

            同樣,在執行刪除前,首先使用beginTransaction()方法創建一個新Hibernate會話和一個新Hibernate事務,然后把要刪除的對象Load進來,接下來調用session.delete()方法來刪除指定對象。

            如果要刪除的是集合中的對象,那么可以通過一個迭代來逐個刪除,如例程6中刪除courses的方法。

            測試

            在這里提供了在JSP中調用MapTestBean進行測試的程序,具體代碼見maptest.jsp文件。在進行測試前,請確保連接數據庫的配置完好,并且每個持久對象的配置都沒有錯誤。如果配置出現困難,請參考本文的源代碼。

            行動起來

            經過兩篇文章由淺入深的學習,希望能夠起到拋磚引玉的作用,相信讀者對Hibernate的認識已經有一個整體的把握。Hibernate由于它的易用性和良好的移植性等特點,逐漸在企業級應用開發中廣泛使用。Hibernate官方網站提供了非常好的使用手冊,您可以參考它。如果您并非精通JDBC并且不想學習它,不妨考慮使用Hibernate;如果您在使用實體Bean之類的持久框架遇到困難,也許Hibernate可以助你一臂之力!

          posted on 2006-06-26 09:28 水煮三國 閱讀(153) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿(4)

          隨筆分類(85)

          隨筆檔案(89)

          文章分類(14)

          文章檔案(42)

          收藏夾(37)

          java

          oracle

          Sybase

          搜索

          •  

          積分與排名

          • 積分 - 211178
          • 排名 - 265

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 阳新县| 海安县| 吉木萨尔县| 蕉岭县| 南部县| 博罗县| 桃江县| 涞水县| 岳普湖县| 仙居县| 民县| 拉孜县| 阳春市| 通州市| 池州市| 竹北市| 澳门| 门头沟区| 济南市| 奉化市| 宿松县| 嘉峪关市| 浦城县| 甘泉县| 鞍山市| 西安市| 江阴市| 宝山区| 长岭县| 旺苍县| 沽源县| 离岛区| 徐水县| 沐川县| 梁山县| 平安县| 丰都县| 长春市| 公主岭市| 固始县| 阿拉善右旗|