小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

在Hibernate中實(shí)現(xiàn)復(fù)雜的數(shù)據(jù)映射

 亂⑦⑧糟 2006-07-27





  在前一篇文章《使用Hibernate來(lái)實(shí)現(xiàn)持久對(duì)象》中,介紹了Hibernate的基本概念,然后用實(shí)例演示了怎么在Web應(yīng)用中使用Hibernate來(lái)封裝持久數(shù)據(jù)對(duì)象。然而在現(xiàn)實(shí)的項(xiàng)目中,我們往往需要操作多個(gè)數(shù)據(jù)表,并且多個(gè)表之間往往存在復(fù)雜的關(guān)系,在本文,將介紹怎么在Hibernate中描述多個(gè)表的映射關(guān)系,并且演示怎么操作關(guān)系復(fù)雜的持久對(duì)象。

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

  案例介紹

  在第一篇文章中,我們對(duì)一個(gè)表進(jìn)行了簡(jiǎn)單的封裝。在這篇文章中,我們討論更加復(fù)雜的情況。

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


圖1 實(shí)體之間的映射關(guān)系

  在上面的數(shù)據(jù)模型圖中,Student是所有表的核心,它和Classes表是一對(duì)多的關(guān)系,和Course表是多對(duì)多的關(guān)系(通過(guò)Student_Course_Link表來(lái)鏈接),和Address表是一對(duì)一的關(guān)系。

  通過(guò)分析,我們可以把上面的數(shù)據(jù)模型轉(zhuǎn)換成如下的Java持久對(duì)象,如圖2所示。


圖2 持久對(duì)象之間的關(guān)系

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

  創(chuàng)建Hibernate持久對(duì)象

  已經(jīng)對(duì)數(shù)據(jù)模型經(jīng)過(guò)了分析,現(xiàn)在就可以創(chuàng)建持久對(duì)象了。持久對(duì)象之間的關(guān)系由圖2所示的類(lèi)圖指定。

  我們首先來(lái)看Student類(lèi),它是這個(gè)關(guān)系映射的核心,代碼如例程1所示。

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

package com.hellking.study.hibernate;

import java.util.Set;
/**
 *在hibernate中代表了Students表的類(lèi)。
 */
public class Student
{
   /**屬性,和students表中的字段對(duì)應(yīng)**/
   private String id;
   private String name;
   /**和其它類(lèi)之間的映射關(guān)系**/
   private Set courses;
   private Classes classes;
   private Address address;
  
    /**屬性的訪問(wèn)方法,必須是公共的方法**/
    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;
 }
 
 /**操作和其它對(duì)象之間的關(guān)系**/
 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類(lèi)中,由于Students表和Classes的表是多對(duì)一的關(guān)系,故它包含了一個(gè)類(lèi)型為Classes的classes屬性,它的實(shí)際意義是一個(gè)學(xué)生可以有一個(gè)班級(jí);Students表和Address的表是一對(duì)一的關(guān)系,同樣也包含了一個(gè)類(lèi)型為Address的address屬性,它的實(shí)際意義是一個(gè)學(xué)生有一個(gè)地址;Students表和Course是多對(duì)多的關(guān)系,故它包含了一個(gè)類(lèi)型為java.util.Set的course屬性,它的實(shí)際意義是一個(gè)學(xué)生可以學(xué)習(xí)多門(mén)課程,同樣,某個(gè)課程可以由多個(gè)學(xué)生來(lái)選修。

  Classes對(duì)象和Student對(duì)象是一對(duì)多的關(guān)系。Classes對(duì)象包含一個(gè)類(lèi)型為java.util.Set的students屬性,它的代碼如例程2所示。

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

package com.hellking.study.hibernate;

import java.util.Set;
/**
 *在hibernate中代表了Classes表的類(lèi)。
 */
public class Classes
{
   /**屬性,和classes表的字段一致**/
   private String id; 
   private String name;
   /**和其它類(lèi)之間的映射關(guān)系**/
   private Set students;
  
   /**屬性的訪問(wèn)方法,必須是公共的方法**/
   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;
 }
 
 /**操作和其它對(duì)象之間的關(guān)系**/
 public void setStudents(Set stud)
 {
  this.students=stud;
 }
 public Set getStudents()
 {
  return this.students;
 }
}

  Course持久對(duì)象在前一篇文章已經(jīng)介紹,在這里就不再列舉。Address持久對(duì)象比較簡(jiǎn)單,除了表字段定義的屬性外,沒(méi)有引入其它的屬性,請(qǐng)參考本文的代碼。

  描述對(duì)象之間的關(guān)系

  現(xiàn)在我們已經(jīng)編寫(xiě)好了持久對(duì)象,下面的任務(wù)就是描述它們之間的關(guān)系。首先我們看Student持久對(duì)象的描述,如例程3所示。

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

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate./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多對(duì)多的關(guān)系-->
         <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之間多對(duì)一的關(guān)系-->
          <many-to-one
            name="classes"
            class="com.hellking.study.hibernate.Classes"
            cascade="none"
            outer-join="auto"
            update="true"
            insert="true"
            column="ClassesId"
        />
       
<!-- 描述Student和Address之間一對(duì)一的關(guān)系-->       
 <one-to-one
            name="address"
            class="com.hellking.study.hibernate.Address"
            cascade="none"
            outer-join="auto"
            constrained="false"
        />      
    </class>
</hibernate-mapping>

  在Student.hbm.xml描述符中,共描述了三種關(guān)系。第一種是Student和Address之間一對(duì)一的關(guān)系,它是最簡(jiǎn)單的關(guān)系,使用:

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

  來(lái)描述,這里的name表示的是Student對(duì)象中名稱(chēng)為address的屬性;class表示的是address屬性的類(lèi)型:com.hellking.study.hibernate.Address。

  接下來(lái)看Student和Classes之間多對(duì)一的關(guān)系,使用:

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

  來(lái)描述。同樣,name表示的是Student對(duì)象中名稱(chēng)為classes的屬性;class表示的是classes屬性的類(lèi)型,column表示Student表引用Classes表使用的外部鍵名稱(chēng)。對(duì)應(yīng)的,在Classes類(lèi)中也引用了Student類(lèi),它使用了以下的描述符來(lái)描述這個(gè)關(guān)系:

        <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之間多對(duì)多關(guān)系時(shí),使用了以下的方法:

        <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>

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

  <key column="StudentId">

  指定了Student對(duì)象在Student_Course_Link鏈接表中的外部鍵。對(duì)應(yīng)的,在Course持久對(duì)象使用了以下的描述符來(lái)描述這個(gè)關(guān)系:

        <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>

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

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

  使用映射關(guān)系

  下面我們開(kāi)發(fā)一個(gè)簡(jiǎn)單的實(shí)例來(lái)測(cè)試這個(gè)映射。持久對(duì)象使用最頻繁的操作是增加數(shù)據(jù)、查詢(xún)數(shù)據(jù)、刪除數(shù)據(jù)、更新數(shù)據(jù)。對(duì)于更新數(shù)據(jù)的操作的情況,多個(gè)表的操作和單個(gè)表沒(méi)有兩樣,在這里不舉例了。

  添加數(shù)據(jù)到數(shù)據(jù)庫(kù)

  我們?cè)谶@里測(cè)試前三種操作,首先來(lái)看添加數(shù)據(jù)到數(shù)據(jù)庫(kù)的情況,如例程4所示。

  例程4 測(cè)試持久對(duì)象之間的映射關(guān)系之添加數(shù)據(jù)(MapTestBean.java部分代碼)

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

  在例程4中,添加數(shù)據(jù)到數(shù)據(jù)庫(kù)之前,首先設(shè)置持久對(duì)象的各個(gè)屬性,如:

  student.setName("hellking2");

  這種設(shè)置屬性的方式和普通的類(lèi)沒(méi)有什么區(qū)別,設(shè)置完所有的屬性后,就設(shè)置持久對(duì)象之間的關(guān)系,如:

  student.setAddress(addr);

  如果存在對(duì)象之間的多重關(guān)系,那么可能需要把對(duì)象保存在Set集合中,然后再進(jìn)行設(shè)置,如:

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

  當(dāng)設(shè)置完所有的屬性和對(duì)象關(guān)系之后,就可以調(diào)用:

  session.save(persistentObject);

  方法把持久對(duì)象保存到Hibernate會(huì)話(huà)中。最后,調(diào)用endTransaction來(lái)提交事務(wù),并且關(guān)閉Hibernate會(huì)話(huà)。

  數(shù)據(jù)查詢(xún)

  在復(fù)雜的實(shí)體對(duì)象映射中,往往查詢(xún)也比較復(fù)雜。作為演示,我們?cè)谶@里也提供了幾個(gè)查詢(xún)方法,如例程5所示。

  例程5 測(cè)試持久對(duì)象之間的映射關(guān)系之查詢(xún)數(shù)據(jù)(MapTestBean.java部分代碼)

    /**
     *獲得某個(gè)給定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;
   
    }
   
    /**
     *獲得某個(gè)給定studentid的Student的所有課程
     */
    public Set getCourses(String id)throws HibernateException
    {
     beginTransaction();     
     Student st=(Student)session.load(Student.class,id);
      endTransaction(false);   
     return st.getCourses();
    }
   
    /**
     *測(cè)試獲得某個(gè)給定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();
    }

  這里提供了三種查詢(xún)方法,分別是:

  查詢(xún)給定id的Student的Address信息;
  查詢(xún)給定id的Student的所有Courses信息;
  查詢(xún)給定id的Student所屬的Classes信息。

  在查詢(xún)時(shí),首先使用beginTransaction()方法創(chuàng)建一個(gè)Hibernate會(huì)話(huà)對(duì)象,并且開(kāi)始一個(gè)新Hibernate事務(wù);然后通過(guò)session.load()方法獲得給定ID的Student對(duì)象,如:

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

  最后調(diào)用student.getXXX()方法返回指定的對(duì)象。

  刪除數(shù)據(jù)

  在表的關(guān)系比較復(fù)雜時(shí),要?jiǎng)h除數(shù)據(jù),往往存在級(jí)聯(lián)刪除的情況,由于級(jí)聯(lián)刪除的情況比較復(fù)雜,在這里就不舉例了。假設(shè)我們要?jiǎng)h除和某個(gè)給定id的student對(duì)象的所有相關(guān)的記錄,就可以使用例程6所示的方法。

  例程6 測(cè)試持久對(duì)象之間的映射關(guān)系之刪除數(shù)據(jù)(MapTestBean.java部分代碼)

    /**
     *刪除和某個(gè)學(xué)生相關(guān)的所有信息
     *(這里只是測(cè)試,我們暫且不說(shuō)這種操作的意義何在)。
     */
    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());
     /**
      *逐個(gè)刪除course。
      */
        for(Iterator it=st.getCourses().iterator();it.hasNext();)
        {
         Course c=(Course)it.next();
         session.delete(c);
        }
        //最后,刪除student對(duì)象。
     session.delete(st);
     endTransaction(true); 
    }

  同樣,在執(zhí)行刪除前,首先使用beginTransaction()方法創(chuàng)建一個(gè)新Hibernate會(huì)話(huà)和一個(gè)新Hibernate事務(wù),然后把要?jiǎng)h除的對(duì)象Load進(jìn)來(lái),接下來(lái)調(diào)用session.delete()方法來(lái)刪除指定對(duì)象。

  如果要?jiǎng)h除的是集合中的對(duì)象,那么可以通過(guò)一個(gè)迭代來(lái)逐個(gè)刪除,如例程6中刪除courses的方法。

  測(cè)試

  在這里提供了在JSP中調(diào)用MapTestBean進(jìn)行測(cè)試的程序,具體代碼見(jiàn)maptest.jsp文件。在進(jìn)行測(cè)試前,請(qǐng)確保連接數(shù)據(jù)庫(kù)的配置完好,并且每個(gè)持久對(duì)象的配置都沒(méi)有錯(cuò)誤。如果配置出現(xiàn)困難,請(qǐng)參考本文的源代碼。

  行動(dòng)起來(lái)

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



    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多