hibernate 关系映射

    首先,我们知道hibernate是一个ORM框架,ORM的全称是(Object Relational Mapping),既对象关系映射,那么hibernate有几种对象关系映射呢?接下来我们来一一举例出

    Hibernate在实现ORM功能的时候主要用到的文件有:映射类(*.java)、映射文件(*.hbm.xml)和数据库配置文件(*hibernate.cfg.xml)

 

    编写 Emp类

        

     编写Dept类

  

1.多对一关联映射(many-to-one):

接下来,我们来编写实体类的映射文件

 

/*
  *查询员工所在的部门,多对一关系
  * */
  @Test
public void test01(){
      /*调用HibernateUtil工具类的getSession()方法获取session*/
      Session session = HibernateUtil.getSession();
      /*延迟加载出员工对象*/
      Emp emp = session.load(Emp.class, 1);
      /*输出员工所在的部门名称*/
      System.out.println(emp.getDept().getDeptname());

  }

/*
* 多对一单项关联
* */
@Test
 public  void testmanytoone(){
     /*调用HibernateUtil工具类的getSession()方法获取session*/
    Session session = HibernateUtil.getSession();
    /*创建Transaction事务*/
    Transaction tr=session.beginTransaction();
       /*创建部门对象*/
    Dept dept=new Dept();
    dept.setDeptname("发财二部");
     /*创建员工对象*/
    Emp emp=new Emp();
    emp.setEmpname("许先生");
    /*将dept对象放入员工Emp对象中*/
    emp.setDept(dept);
    session.save(dept);
    session.save(emp);
      /*提交事务*/
    tr.commit();
}

@Test
/*
* 按照指定的部门编号查询对应的员工信息
* */
public void test3(){
     /*调用HibernateUtil工具类的getSession()方法获取session*/
    Session session = HibernateUtil.getSession();
    /*创建Transaction事务*/
    Transaction tx=session.beginTransaction();
    /*编写hql语句,按照指定的部门编号查询对应的员工信息*/
    String hql="from Emp e where e.dept.deptno=1";
     /*将生成的Bean为query对象装入list*/
    Query query = session.createQuery(hql);
    List<Emp> list = query.list();
    /*输出对应的部门的员工名称*/
    for (Emp item : list) {
        System.out.println(item.getEmpname());
    }
    tx.commit();
}
/*查询所有的员工和各自对应的部门*/
@Test
public void test4(){
  /*调用HibernateUtil工具类的getSession()方法获取session*/
    Session session = HibernateUtil.getSession();
     /*创建Transaction事务*/
    Transaction tr =session.beginTransaction();
    /*编写hql,查询所以员工*/
    String hql="from Emp";
     /*将生成的Bean为query对象装入list*/
    Query query = session.createQuery(hql);
    List<Emp> list = query.list();
    /*输出所以员工和每个员工对应的部门*/
    for (Emp emp:list) {
        System.out.println(emp.getDept().getDeptname());
        System.out.println(emp.getEmpname()+"----------------"+emp.getEmpno());
    }
}
 /*修改员工的部门编号*/
 @Test
public  void  test5(){
     Session session = HibernateUtil.getSession();
     Transaction tr =session.beginTransaction();
     Emp emp = session.load(Emp.class, 1);
     Dept dept = session.load(Dept.class, 2);
     emp.setDept(dept);
     tr.commit();
 }

 


 2. 一对多关联映射(one-to-many):


这个时候我们需要在Dept实体加入Set集合

那么为什么要用set集合而不用list呢
 首先,你要清楚List和Set的区别:List是有序和可重复;Set是无序,但是不能重复.
其次,在一对多关联中.想象一下这种情况:你要更新从表记录;
从List中得到从表的一个对象引用,然后你对这样对象修改后,又放回List,你的List中就包括两个从表对象的引用.你在保存时,这两个引用,你觉得会保存两次还是一次?
而如果是Set,你得到从表对象的引用,之后修改从表对象的内容,你再往Set里面放,Set里面因为已经有这个从表对象的引用,就不会再给里面加.这样,你的Set里面还是只有一个从表对象的引用.这样你保存,这个从表对象只保存一次.

映射文件 Dept.hbm.xml
 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC
 3         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 4         "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 5 <hibernate-mapping package="cn.hibernate.day04.entity">
 6     <!--实体 name=实体端的内容   column=DB端的内容-->
 7     <class name="Dept" table="DEPT">
 8         <!--和底层数据表对应的主键   业务意义-->
 9         <id name="deptno" column="DEPTNO">
10            <generator class="native"></generator>
11         </id>
12         <property name="deptname" column="DEPTNAME" length="32"></property>
13         <!--一对多-->
14         <set name="emps" cascade="save-update,persist" table="Emp" >
15             <key column="deptno"></key>
16             <one-to-many class="Emp"></one-to-many>
17         </set>
18     </class>
19 </hibernate-mapping>


接下来是列子
  /*查询所有的部门,并把部门所对应的员工信息检索出来,一对多关系*/
@Test
 public void testonetomany(){
    /*编写hql语句:查询所有部门*/
     String hql="from Dept";
     /*调用HibernateUtil工具类的getSession()方法获取session*/
    Session session = HibernateUtil.getSession();
    /*将生成的Bean为query对象装入list*/
    Query query =  session.createQuery(hql);
    List<Dept> list = query.list();
    /*遍历部门输出部门名称*/
    for (Dept dept:list) {
        System.out.println(dept.getDeptname()+"--------------");
        /*根据部门实体中的Set集合获取员工信息,遍历输出*/
        for (Emp emp:dept.getEmps()) {
            System.out.println(emp.getEmpname()+"--------------");
        }
    }
}


/*添加部门和员工信息,一对多关系*/
@Test
 public  void  testsaveDept(){
     /*调用HibernateUtil工具类的getSession()方法获取session*/
    Session session = HibernateUtil.getSession();
    /*创建Transaction事务*/
    Transaction tx=session.beginTransaction();
    /*创建部门对象*/
    Dept dept=new Dept();
    dept.setDeptname("财务部");
    /*创建员工对象*/
    Emp emp=new Emp();
    emp.setEmpname("笑醒");
    /*调用add()方法将emp对象放入dept,如果不写,添加的时候不会添加员工信息*/
    dept.getEmps().add(emp);
    session.save(dept);
    /*提交事务*/
    tx.commit();
}

 



  注意:它与多对一的区别是维护的关系不同

          *多对一维护的关系是:多指向一的关系,有了此关系,加载多的时候可以将一加载上来
          *一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来

 

3.多对多单向关联(many-to-many)

  首先我们需要两个拥有多对多关系的类,生活中多对多关系的列子很多,随便就能列出了,比如学生和老师,程序员和项目,那么我们用程序员员工和项目来做列子

 

//员工实体
public class Employee {
    private Integer empid;
    private String empname;
    private Set<Project> projects = new HashSet<Project>();
}

 

/**
 * Created by Happy on 2017-09-26.
 * 工程实体
 */
public class Project {
    private Integer proid;
    private String proname;
    private Set<Employee> employees=new HashSet<Employee>();

 

接下来我们来写两个配置文件

Project.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.hibernate.day05.entity">
    <!--实体 name=实体端的内容   column=DB端的内容-->
    <class name="Project" table="PROJECT">
        <!--和底层数据表对应的主键   业务意义-->
        <id name="proid" column="PROID">
           <generator class="native"></generator>
        </id>
        <property name="proname" column="PRONAME" length="32"></property>
    </class>
</hibernate-mapping>

Employee.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.hibernate.day05.entity">
    <!--实体 name=实体端的内容   column=DB端的内容-->
    <class name="Employee" table="EMPLOYEE">
        <!--和底层数据表对应的主键   业务意义-->
        <id name="empid" column="EMPID">
           <generator class="native"></generator>
        </id>
        <property name="empname" column="EMPNAME" length="32"></property>
        <!--
          Table属性:中间表(集合表)
          key子元素:集合外键(引用当前表主键的外键),里面的Column指的是在中间表中的列名
          many-to-many子元素:里面的class属性是指关联的类型,column是指引用Project的主键值
      -->
        <set name="projects" cascade="save-update" table="EMPPRO" >
            <key column="EPMRID"></key>
            <many-to-many class="Project" column="RPROID"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

接下来是测试列子

  /*添加多对多单向关联信息*/
    @Test
    public  void  test01(){
         /*调用HibernateUtil工具类的getSession()方法获取session*/
        Session session=HibernateUtil.getSession();
         /*创建Transaction事务*/
        Transaction tx=session.beginTransaction();
          /*创建员工对象*/
        Employee emp1=new Employee();
        emp1.setEmpname("没事了大疯狂拉升");
        /*创建项目对象*/
        Project pro1=new Project();
        pro1.setProname("海淀花园");
        Project pro2=new Project();
        pro2.setProname("海上花园");
        emp1.getProjects().add(pro1);
        emp1.getProjects().add(pro2);
        session.save(emp1);
        session.save(pro1);
        session.save(pro2);
        tx.commit();
    }

    /*查询项目Set集合中对象的个数*/
     @Test
    public  void  test02(){
         Session session = HibernateUtil.getSession();
         Transaction transaction = session.beginTransaction();
         Employee employee = session.load(Employee.class, 1);
         Set<Project> projects=employee.getProjects();
         System.out.println(projects.size());

     }

 

4.多对多双向关联(many-tomany)

需要在Project.hbm.xml加入set

 

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.hibernate.day05.entity">
    <!--实体 name=实体端的内容   column=DB端的内容-->
    <class name="Project" table="PROJECT">
        <!--和底层数据表对应的主键   业务意义-->
        <id name="proid" column="PROID">
           <generator class="native"></generator>
        </id>
        <property name="proname" column="PRONAME" length="32"></property>
        <set name="employees" table="EMPPRO" >
            <key column="RPROID" ></key>
            <many-to-many column="EPMRID" class="Employee" ></many-to-many>
        </set>
    </class>
</hibernate-mapping>

 

 

测试类

  /*添加多对多单向关联信息*/
    @Test
    public  void  test01(){
         /*调用HibernateUtil工具类的getSession()方法获取session*/
        Session session=HibernateUtil.getSession();
         /*创建Transaction事务*/
        Transaction tx=session.beginTransaction();
          /*创建员工对象*/
        Employee emp1=new Employee();
        emp1.setEmpname("没事了大疯狂拉升");
        /*创建项目对象*/
        Project pro1=new Project();
        pro1.setProname("海淀花园");
        Project pro2=new Project();
        pro2.setProname("海上花园");
        emp1.getProjects().add(pro1);
        emp1.getProjects().add(pro2);
        session.save(emp1);
       /* session.save(pro1);
        session.save(pro2);*/
        tx.commit();
    }

 

关联关系中常用属性

1.级联(cascade)

 我们以部门和员工的关系为例讲解一对多关联关系映射时,删除部门时,如果部门有关联的员工且inverse属性为false,那么由于可以维护关联关系,它就会先把关联的员工的外键列设为null值,再删除自己。但是此刻希望删除部门时,就附带着把该部门下的所有员工都删掉,这时就需要引入cascade属性了。

 

当Hibernate持久化一个临时对象时,在默认情况下,它不会自动持久化所关联的其他临时对象,而是会抛出TransientObjectException。如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。如:

 

2. set元素的inverse属性

 inverse有两属性:

1 .false    设置为false,则为主动方,由主动方负责维护关联关系,默认是false

2 .true    设置为true,则不为主动方,并且不负责维护关联关系,而是由不包含这个关系的一方来维护这个关系

 

3.order_by     其作用就是对集合中的数据进行排序

 

posted @ 2017-12-28 17:48  许海峰  阅读(147)  评论(0编辑  收藏  举报