班级学生一对多表关联

  • 建立关联关系的话首先至少要有两个表,那就要有两个实体类,通常是一对多的关系,比如学生和班级,可以在其中一个类加入另一个类的实例,比如在学生中包含班级这个类(如果是班级中包含学生的话那应该是一个班级包含一个学生集合)

     public class Student {
    
         private long id;
         private String name;
         private Class c; //学生只有一个班级,多对一
    }
    
  • 映射文件中加入外键声明,多的这个表一定要加

    <!--在学生表中插入一个外键-->
    <many-to-one name="c" column="classId" class="com.java1234.model.Class" cascade="save-update"></many-to-one>
    
  • 一的这边也可以声明和多的之间的关联(不是必要)

     //类
     public class Class {
    
         private long id;
         private String name;
         private Set<Student> students=new HashSet<Student>();
    }
    
    //映射文件
    <!-- 因为是一对多,所以class表不会多出下面字段,只是建立一种关联而已,不写也可以(写了的话获取班级的同时会自动获取学生集合),但学生表那边一定要写 -->
     <set name="students" cascade="save-update" inverse="true"> <!-- 加上save-update可以在只保存class的情况下顺便保存student;加上inverse就能在多的一端维护外键;加上cascade="delete"可以进行级联删除 -->
         <key column="classId"></key> <!-- 外键名 --> 
         <one-to-many class="com.java1234.model.Student"/>
     </set>
    
    • 比如上面这个set集合如果不设置的话,那么下面打印的将是0,因为班级获取不到学生

       public void testInversse() {
       Class c=(Class)session.get(Class.class, Long.valueOf(1));
       Set<Student> students=c.getStudents();
       System.out.println(students.size());
      }
      
  • 最后插入数据的时候要在学生中设置好班级

    Class c=new Class();
    c.setName("08计本");
    session.save(c);
    
    Student s1=new Student();
    s1.setName("张三");
    s1.setC(c);
    
    Student s2=new Student();
    s2.setName("李四");
    s2.setC(c);
    
    session.save(s1);
    session.save(s2);
    
  • 经过上面学生类和学生映射文件这两步,学生这个表就会自动关联到班级表的主键。

    级联

  • 学生映射文件中,在标签里面,cascade默认是“none”,假如我们希望在持久化多的一端时自动级联保存和更新一的一端,我们可以把cascade设置成“save-update”。那么这个class自己不保存也可以跟着引用了它的student保存下来。反过来,在班级映射文件中加入该标签,则可以使student随着class保存而保存。

    Class c=new Class();
    c.setName("08计本");
    // session.save(c); 不保存,在<many-to-one>标签中加个属性cascade属性即可随多的一方(Student)保存
    
    Student s1=new Student();
    s1.setName("张三");
    s1.setC(c);
    
    Student s2=new Student();
    s2.setName("李四");
    s2.setC(c);
    
    session.save(s1);
    session.save(s2);
    

    inverse属性

  • 剪除多余hql,提高性能

    <set name="students" cascade="save-update" inverse="true"> <!-- 加上save-update可以在只保存class的情况下顺便保存student;加上inverse就能在多的一端维护外键;加上cascade="delete"可以进行级联删除 -->
        <key column="classId"></key> <!-- 外键名 --> 
        <one-to-many class="com.java1234.model.Student"/>
    </set>
    
  • 比如上面班级配置文件中的inverse属性,加上之后可以提高以下程序的性能

    //先添加两条没有关联的数据
    @Test
    public void testAdd() {
        Class c=new Class();
        c.setName("09计本");
    
        Student s1=new Student();
        s1.setName("王五");
    
        session.save(c);
        session.save(s1);
    }
    
    //把这两条数据查出来之后再建立联系
    @Test
    public void testInversse() {
        Class c=(Class)session.get(Class.class, Long.valueOf(1));
        Student s=(Student)session.get(Student.class, Long.valueOf(1));
    
        //加了inverse之后可以使第二行不生效(因为它本来就没用,除了多一句多余的hql拖慢性能)提高性能,一般都是在多的一端保存即可
        s.setC(c); //在学生中添加班级,会在学生表中增加班级外键
        c.getStudents().add(s); //在班级中添加学生,会在学生表中增加学生外键
        //这样就会生成hql,在这个学生中加入这个班级的外键
    }
    

    级联删除

  • 删除被关联的表时顺便删除父表

    /*
     * 这样运行应该是报错的,因为class表被关联,加上属性cascade="delete"后才能进行级联删除,将学生表记录一并删掉
    */
    @Test
    public void testDeleteClassCascade() {
        Class c=(Class)session.get(Class.class, Long.valueOf(1));
        session.delete(c);
    }
    

    自身关联

  • 自身字段关联自身字段,比如下面一个菜单的例子

    • 数据库

      //类
      public class Node {

      private long id;
      private String name;
      
      private Node parentNode; //父节点
      
      private Set<Node> childNodes=new HashSet<Node>(); //子节点
      

      }

      //映射文件




      //保存数据
      @Test
      public void testSaveMenu() {

      Node node=new Node();
      node.setName("根结点");
      
      Node subNode1=new Node();
      subNode1.setName("子结点1");
      
      Node subNode2=new Node();
      subNode2.setName("子结点2");
      
      subNode1.setParentNode(node);
      subNode2.setParentNode(node);
      
      session.save(subNode1);
      session.save(subNode2);
      

      }

      代码实例:eclipse->HibernateCrud