hibernate02 关系操作 多对一单向双向

来源:互联网 发布:sicp 知乎 编辑:程序博客网 时间:2024/06/08 19:48


一、 多对一单向关联


      *****************************************************************************************
       类:
         public class Classes implements Serializable {
              private Long cid;            
              private Set<Student> students;
              // set/get属性
         }
         
         public class Student implements Serializable {
              private Long sid;                
              // set/get属性
         }
         
       ----------------------------------------------------------------------------------------          
       配置文件:
          Student.hbm.xml
              <hibernate-mapping>
                <class name="cn.itcast.oneToMany.domain.Student">                  
                    <id name="sid" length="3">
                        <generator class="increment"></generator>
                    </id>                                     
                </class>
              </hibernate-mapping>
              
        ----------------------------------------------------------------------------------------
          
          Classes.hbm.xml
              <hibernate-mapping>
                    <class name="cn.itcast.oneToMany.domain.Classes">            
                        <id name="cid" length="5" type="java.lang.Long">
                          <generator class="increment"></generator>
                        </id>           
                     
                      <set name="students"  cascade="all" inverse="true">
                          <!-- key用来描述外键 -->
                          <key>
                              <column name="cid"></column>
                          </key>
                          <one-to-many class="cn.itcast.oneToMany.domain.Student"/>
                      </set>            
                    </class>
              </hibernate-mapping>
          
              注:
                set元素对应类中的set集合,通过set元素使classes表和student表建立关联
                属性:
                    cascade: 级联操作  描述对象和对象之间的关系
                        save-update 
                            当保存班级的时候,对学生进行怎样的操作:
                              若学生对象在数据库中没有对应的值,这个时候就会执行save操作
                              若学生对象在数据库中有对应的值,将该持久化对象与快照进行比对,
                              如果一致,则什么也不做,如果不不一致,则发出update语句
                        delete
                        all
                        注: 把session.save/update一个对象的操作为显式操作,级联的操作为隐式操作
                            当隐式操作一个对象的时候,必须在配置文件中设置cascade属性
                    
                    inverse: 维护关系(即外键)   描述对象与外键之间的关系
                        true   不维护关系
                        false   维护关系 默认值
                        default false    
                        注: inverse在那个对象的配置文件,就是该对象维护另一个对象
                            inverse所在的映射文件classes对classes与student之间的关系是否进行维护
                             维护关系体现在两点:
                                 1、在映射文件中inverse的值必须是false/default
                                 2、必须在客户端代码上建立两者之间的关系,更新外键


                子元素:
                    key是通过外键的形式使俩张表建立关联,column对应外键的字段
                    one-to-many是通过类的形式让俩个类建立关联


       *****************************************************************************************
       


      例子:
      *****************************************************************************************
      
          public class OneToManySingleTest {

              // 1. 新建一个班级
              @Test
              public void testSaveClasses(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                Classes classes = new Classes();
                classes.setCname("传智上海云一期SB");
                classes.setDescription("很牛SB");
                session.save(classes);
                transaction.commit();
                session.close();
              }
              
              
              // 2. 新建一个学生
              @Test
              public void testSaveStudent(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                Student student = new Student();
                student.setSname("班长");
                student.setDescription("技术很牛");
                session.save(student);
                transaction.commit();
                session.close();
              }
              
              
              // 3.0. 方式1: 新建一个班级的同时新建一个学生 
              @Test
              public void testSaveClass_Student(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Classes classes = new Classes();
                classes.setCname("传智上海云二期");
                classes.setDescription("很牛X");
                
                Student student = new Student();
                student.setSname("班长");
                student.setDescription("技术很牛X");
                
                session.save(classes);
                session.save(student); // 该方式若有n个学生,则必须保存n次
                transaction.commit();
                session.close();
              }
              
              
              // 3.1. 方式2: 新建一个班级的同时新建一个学生  在保存班级的同时,级联保存学生
              @Test
              public void testSaveClass_cascade_Student_save(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Classes classes = new Classes();
                classes.setCname("传智上海云三期");
                classes.setDescription("很牛XX");
                
                Student student = new Student();
                student.setSname("班长");
                student.setDescription("技术很牛XX");
                
                // 建立classes与student之间的联系
                Set<Student> students = new HashSet<Student>();
                students.add(student);
                classes.setStudents(students);
                
                // 保存班级,同时级联保存了学生;  该方式保存学生只须保存一个集合即可
                session.save(classes);
                
                transaction.commit();
                session.close();
              }
              
              
              // 3.2. 方式2: 新建一个班级的同时新建一个学生  在保存班级的同时,级联更新学生
              @Test
              public void testSaveClass_cascade_Student_update(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Classes classes = new Classes();
                classes.setCname("传智上海云四期");
                classes.setDescription("很牛XXX");
                
                Student student = (Student) session.get(Student.class, 1L);
                student.setSname("小班长");  // 与快照进行比对,修改了,所以执行update语句 
                
                // 建立classes与student之间的联系
                Set<Student> students = new HashSet<Student>();
                students.add(student);
                classes.setStudents(students);
                
                // 保存班级,同时级联保存了学生;  该方式保存学生只须保存一个集合即可
                session.save(classes);
                
                transaction.commit();
                session.close();
              }
              
              
              // 3.3. 已经存在一个班级,已经存在一些学生,新建一个学生并添加到该班级中
              @Test
              public void testUpdateClasses_Cascade_Student_Save(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Student student = new Student();
                student.setSname("班花");
                student.setDescription("稀有人物");
                Classes classes = (Classes) session.get(Classes.class, 5L);
                classes.getStudents().add(student);
                
                transaction.commit();
                session.close();
              }
              
              
              // 3.4. 已经存在一个班级,已经存在一些学生,修改该班级的学生信息
              @Test
              public void testUpdateClasses_Cascade_Student_Update(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Classes classes = (Classes) session.get(Classes.class, 5L);
                Set<Student> students = classes.getStudents(); // 班号为5的班级的学生集合
                for(Student student:students){
                  student.setDescription("亚历山大");
                }
                
                transaction.commit();
                session.close();
              }
              
              
              /**
               * 4. 已经存在一个班级,新建一个学生,建立学生与班级的关系
               * 通过更新班级级联保存学生: cascade 
               * 建立班级和学生之间的关系: inverse
               */
              @Test
              public void testSaveStudent_R_1(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Classes classes = (Classes) session.get(Classes.class, 1L);
                Student student = new Student();
                student.setSname("技术班长");
                student.setDescription("大牛");
                classes.getStudents().add(student);
                
                transaction.commit();
                session.close();
              }
              
              
              // 5. 已经存在一个学生,新建一个班级,把学生加入到该班级中
              @Test
              public void testSaveClassess_R(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Student student = (Student) session.get(Student.class, 2L);
                
                Classes classes = new Classes();
                classes.setCname("老毕基础加强班");
                classes.setDescription("必看,杀手锏");
                Set<Student> students = new HashSet<Student>();
                students.add(student);
                classes.setStudents(students);
                
                session.save(classes);
                
                transaction.commit();
                session.close();
              }
              
              
              /**
               *  6. 把一个学生从一个班级转移到另一个班级中
               *  Hibernate: select classes0_.cid as cid0_0_, classes0_.cname as cname0_0_, classes0_.description as descript3_0_0_ from Classes classes0_ where classes0_.cid=?
                Hibernate: select classes0_.cid as cid0_0_, classes0_.cname as cname0_0_, classes0_.description as descript3_0_0_ from Classes classes0_ where classes0_.cid=?
                Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_ from Student student0_ where student0_.sid=?
                Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_ from Student students0_ where students0_.cid=?
                Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_ from Student students0_ where students0_.cid=?
                Hibernate: update Student set cid=null where cid=? and sid=?
                Hibernate: update Student set cid=? where sid=?
               */
              @Test
              public void testTransformClass(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                // 根据数据库语句,不需要解除关系,直接该外键就可以  所以可以省略这俩步
            // Classes classes5 = (Classes) session.get(Classes.class, 5L);
                Classes classes6 = (Classes) session.get(Classes.class, 6L);
                Student student = (Student) session.get(Student.class, 1L);
            // classes5.getStudents().remove(student);
                classes6.getStudents().add(student);
                
                transaction.commit();
                session.close();
              }
              
              
              // 8. 解除一个班级和一些学生的关系
              @Test
              public void testR_Some(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Classes classes = (Classes) session.get(Classes.class, 1L);
                Set<Student> students = classes.getStudents();
                
                
                // 因为要用到角标获取元素,而set无法获取到角标,所以须将set集合转换成list集合
                List<Student> sList = new ArrayList<Student>(students);
                
                // 将id为1号的班级中id为2,3号的学生解除关系
                for(int i=0; i<sList.size(); i++){
                  if(sList.get(i).getSid().longValue()==2||sList.get(i).getSid().longValue()==3){
                    sList.remove(sList.get(i));
                    i--;   // 注: remove取出元素,需要--
                  }
                }
                
                // 再将list集合还原成set集合,并建立与班级的关系
                students = new HashSet<Student>(sList);
                classes.setStudents(students);
                
                
                transaction.commit();
                session.close();
              }
              
              
              
              // 9. 解除该班级和所有学生的关系
              @Test
              public void testRealseAll(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Classes classes = (Classes) session.get(Classes.class, 1L);
                // 方式1 先查询,再清空
            // Set<Student> students = classes.getStudents();
            // students.clear();
                // 方式2  直接将集合置为null,效率更高
                classes.setStudents(null);
                
                
                transaction.commit();
                session.close();
              }
              
              
              // 12.删除学生
              @Test
              public void testDeleteStudent(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Student student = (Student) session.get(Student.class, 3L);
                session.delete(student);
                
                transaction.commit();
                session.close();
              }
              
              
              // 13.1.删除班级 在删除班级之前,解除班级与学生的关系
              // 注: 此时Classes.hbm.xml配置文件中名称为students的set元素的inverse属性为默认值false 维护关系
              //     所以在删除classes的时候hibernate内部会自动解除班级与学生的关系,然后再删除classes
              //     当Classes.hbm.xml配置文件中名称为students的set元素的inverse属性为true 不维护关系时,单项关联无法解决
              @Test
              public void testDeleteClasses_1(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Classes classes = (Classes) session.get(Classes.class, 2L);
                session.delete(classes);
                
                transaction.commit();
                session.close();
              }
              
              
              // 13.2. 删除班级 删除班级的同时删除学生
              // 注: 此时cascade为all  inverse为true
              @Test
              public void testDeleteClasses_cascade(){
                SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                Session session = sessionFactory.openSession();
                Transaction transaction = session.beginTransaction();
                
                Classes classes = (Classes) session.get(Classes.class, 3L);
                session.delete(classes);
                
                transaction.commit();
                session.close();
              }
              


      }
            
      
      *****************************************************************************************  
  
  


  
二 一对多的双向关联        
                
     *****************************************************************************************
     类:
       public class Classes implements Serializable {
            private Long cid;            
            private Set<Student> students;
            // set/get属性
       }
       
       public class Student implements Serializable {
            private Long sid;                
            private Classes classes;
            // set/get属性
       }
       
     ----------------------------------------------------------------------------------------          
     配置文件:
        Student.hbm.xml
            <hibernate-mapping>
              <class name="cn.itcast.oneToMany.domain.Student">                  
                 
                  <id name="sid" length="3">
                      <generator class="increment"></generator>
                  </id>   、
                 
                  <!-- 多对一  column 外键 -->
                  <many-to-one name="classes" class="cn.itcast.oneToMany.domain.Classes" column="cid" cascade="all"></many-to-one>                                  
             
              </class>
            </hibernate-mapping>
            
            注: 一对多的操作,对多的一方操作不需要维护外键(inverse为true),会自动维护;不会发出update语句来维护外键
                若对一的一方操作,需要维护外键(inverse为false),要发出update维护外键的语句
                故一对多对多的一方操作,自动维护外键的关系,效率高;
      ----------------------------------------------------------------------------------------
        
        Classes.hbm.xml
            <hibernate-mapping>
                  <class name="cn.itcast.oneToMany.domain.Classes">            
                      <id name="cid" length="5" type="java.lang.Long">
                        <generator class="increment"></generator>
                      </id>           
                   
                    <set name="students"  cascade="all" inverse="true">
                        <key>
                            <column name="cid"></column>
                        </key>
                        <one-to-many class="cn.itcast.oneToMany.domain.Student"/>
                    </set>            
                  </class>
            </hibernate-mapping>        
            
     *****************************************************************************************  
       
      
     例:
     *****************************************************************************************   
        public class OneToManyDoubleTest {

            // 3. 新建一个班级的同时新建一个学生  
            @Test
            public void testSaveStudent_Cascade_Classes_Save(){
              SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
              Session session = sessionFactory.openSession();
              Transaction transaction = session.beginTransaction();
              
              Student student = new Student();
              student.setSname("班秘");
              student.setDescription("班长的秘书");
              Classes classes = new Classes();
              classes.setCname("老毕的亲子班");
              classes.setDescription("都是老毕的亲戚");
              
              student.setClasses(classes);
              session.save(student);
              
              transaction.commit();
              session.close();
            }
            
            
            // 4. 已经存在一个班级,新建一个学生,建立学生与班级的关系
            // 注:  一对多,从多的一端维护关系效率较高,因为不必维护外键,不需发出update语句
            @Test
            public void testSaveStudent_R(){
              SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
              Session session = sessionFactory.openSession();
              Transaction transaction = session.beginTransaction();
              
              Student student = new Student();
              student.setSname("朱有才");
              student.setDescription("才华横溢");
              Classes classes = (Classes) session.get(Classes.class, 6L);
              
              student.setClasses(classes);
              session.save(student);
              
              transaction.commit();
              session.close();
            }
            
            
            // 8. 解除一个班级和一些学生的关系
            @Test
            public void testRelease_R(){
              SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
              Session session = sessionFactory.openSession();
              Transaction transaction = session.beginTransaction();
              
              Classes classes = (Classes) session.get(Classes.class, 6L);
              Student student1 = (Student) session.get(Student.class, 1L);
              Student student6 = (Student) session.get(Student.class, 6L);
              
              student1.setClasses(null);
              student6.setClasses(null);
              
              transaction.commit();
              session.close();
            }
        }
      *****************************************************************************************
        
        
        
三、总结       
   
    1、 如果让一的一方维护关系,取决于的因素有:
          1.在一的一方的映射文件中,set的inverse属性为default/false
          2.在客户端的代码中,通过一的一方建立关系
          3.session.save/update方法是用来操作表的,和操作关系无关
    
    2、 采用级联的方式通过保存一个对象从而保存关联对象
          1.如果session.save操作的对象是A,这个时候应该看A.hnm.xml文件,看set元素中的cascade属性是否设置有级联保存
          2.在客户端通过A建立关联
          3.在客户端执行session.save(A)
          
    3、 一对多的情况,多的一方维护关系效率比较高
          1.在多的一方many-to-one中没有inverse属性
          2.在客户端通过多的一方建立关联
        
        
        
        
        
        
0 0
原创粉丝点击