免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 973 | 回复: 0
打印 上一主题 下一主题

在Hibernate中实现复杂的数据映射[zz] [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-08-02 14:52 |只看该作者 |倒序浏览
在现实的项目中,我们往往需要操作多个数据表,并且多个表之间往往存在复杂的关系,在本文,将介绍怎么在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)
   
   
        
            
        
     
         
         
              
              
        
         
        
        
        
   
  在Student.hbm.xml描述符中,共描述了三种关系。第一种是Student和Address之间一对一的关系,它是最简单的关系,使用:
  
  来描述,这里的name表示的是Student对象中名称为address的属性;class表示的是address属性的类型:com.hellking.study.hibernate.Address。
  接下来看Student和Classes之间多对一的关系,使用:
  
  来描述。同样,name表示的是Student对象中名称为classes的属性;class表示的是classes属性的类型,column表示Student表引用Classes表使用的外部键名称。对应的,在Classes类中也引用了Student类,它使用了以下的描述符来描述这个关系:
        
              
              
        
  在描述Student和Course之间多对多关系时,使用了以下的方法:
        
              
              
        
  在映射多对多关系时,需要另外使用一个链接表,这个表的名字由table属性指定,链接表包含了两个字段:CourseId和StudentId。以下的描述:
  
  指定了Student对象在Student_Course_Link链接表中的外部键。对应的,在Course持久对象使用了以下的描述符来描述这个关系:
        
              
              
        
  由于其它持久对象的描述基本一样,在这里就不一一列举了,请参考本文的源代码。最后别忘了在hibernate.cfg.xml里增加这几个对象的描述。
        
        
        
        
          /**
  *在数据库中添加数据
  */
  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可以助你一臂之力!


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/2016/showart_38778.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP