hibernate02 關係操作 多對一單向雙向



一、 多對一單向關聯


      *****************************************************************************************
       類:
         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.在客戶端通過多的一方建立關聯
        
        
        
        
        
        
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章