1. 程式人生 > >hibernate中一對多和多對多關係

hibernate中一對多和多對多關係

一對多:

                    一個部門對應多個員工,一個員工只能屬於某一個部門。

                    一個客戶對應多個聯絡人,一個聯絡人只能屬於某一個客戶。 

          建表原則:

                              在多的一方建立外來鍵指向一的一方的主鍵

          客戶為一,聯絡人為多

          建立實體類時:

    /**
     *  Customer(一)中放LinkMan(多)的集合
     */ 

    // 通過ORM方式表示,一個客戶對應多個聯絡人
	// 放置的是多的一方的集合,hibernate預設使用的Set集合
	private Set<LinkMan> linkMans = new HashSet<LinkMan>();
	/**
	 * LinkMan(多)中放Customer(一)的物件
	 */
	// 通過ORM,一個聯絡人只能屬於某一個客戶
	private Customer customer;

          配置對映檔案時:

  多的一方的中的配置檔案中新增配置(在calss標籤中新增):


<!-- 配置一對多的關係 -->	
	<!-- 
	   	set標籤:
			name:多的一方的物件的集合的屬性名稱
	 -->
	<set name="linkMans" >
		<!-- 
			key標籤
				column:多的一方的外來鍵名稱
		 -->
		<key column="lkm_cust_id"></key>
		<!-- 
			one-to-many標籤
				class:多的一方的全路徑
		 -->
		<one-to-many class="domain.LinkMan"/>
	</set>

     

一的一方的中的配置檔案中新增配置(在calss標籤中新增): 

<!--配置一對多的關係  -->
	<!-- 
		many-to-one標籤:
				name	:一的一方在多的一方類中的屬性名稱
				class	:一的一方的類的全路徑
				column	:在多的一方的表中的外來鍵的名稱
	 -->
	 <many-to-one name="customer"  class="domain.Customer" column="lkm_cust_id"></many-to-one>

 

操作:

  一對多關係儲存一邊不行,會報錯,解決方法:級聯操作

    //一對多關係只儲存一邊
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//一個客戶
		Customer customer1 = new Customer();
		customer1.setCust_name("東");
		
		//一個聯絡人
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("甲");
		 
		//設定關係
		linkMan1.setCustomer(customer1);
	
		customer1.getLinkMans().add(linkMan1);
		
		//儲存一邊:不可以,報瞬時物件異常,持久態物件關聯一個瞬時態物件
		session.save(customer1);
		
		transaction.commit();
	}

 

級聯:

級聯儲存或更新:

          在一的一方的配置檔案中新增配置:

                          在set標籤中新增 cascade=“save-update”

/**
 * 級聯儲存或更新操作
 * 		儲存客戶級聯聯絡人,操作主題是客戶物件,需要在客戶對映檔案中配置
 */
public void test(){
	Session session = HibernateUtils.getCurrentSession();
	Transaction transaction = session.beginTransaction();
		
	//一個客戶
	Customer customer1 = new Customer();
	customer1.setCust_name("東");
		
	//一個聯絡人
	LinkMan linkMan1 = new LinkMan();
	linkMan1.setLkm_name("甲");
		 
	//設定關係
	linkMan1.setCustomer(customer1);
	
	customer1.getLinkMans().add(linkMan1);
		
	//儲存一邊:不可以,配置級聯後可以
	session.save(customer1);
		
	transaction.commit();
}

  在多的一方的配置檔案中新增配置:

                          在many-to-one標籤中新增 cascade=“save-update”

 

    /**
	 * 級聯儲存或更新操作
	 * 		儲存聯絡人,操作主題是聯絡人物件,需要在聯絡人對映檔案中配置
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//一個客戶
		Customer customer1 = new Customer();
		customer1.setCust_name("1");
		
		//一個聯絡人
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("2");
		 
		//設定關係
		linkMan1.setCustomer(customer1);
	
		customer1.getLinkMans().add(linkMan1);
		
		//儲存一邊:不可以,配置級聯後可以
		session.save(linkMan1);
		
		transaction.commit();
	}
	

 

 

級聯刪除:

在一的一方的配置檔案中新增配置:

                          在set標籤中新增 cascade=“delete”,delete和save-update可以同時存在

    /**
	 * 級聯刪除:
	 * 		刪除客戶級聯聯絡人
	 * 		刪除客戶,同時刪除聯絡人,在客戶配置檔案中配置級聯刪除:cascade=delete
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//沒有設定級聯刪除,預設情況:修改了聯絡人的外來鍵,刪除客戶
//		Customer customer = session.get(Customer.class, 1l);
//		session.delete(customer);
		
		//刪除客戶,同時刪除聯絡人,在客戶配置檔案中配置級聯刪除:cascade=delete
		Customer customer = session.get(Customer.class, 1l);
		session.delete(customer);
		
		transaction.commit();
	}

 

在多的一方的配置檔案中新增配置:

                          在many-to-one標籤中新增 cascade=“save-update”,delete和save-update可以同時存在

    /**
	 * 級聯刪除:
	 * 		刪除聯絡人級聯客戶
	 * 		刪除聯絡人,同時刪除客戶,在聯絡人配置檔案中配置級聯刪除:cascade=delete
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		
		//刪除聯絡人,同時刪除客戶,在聯絡人配置檔案中配置級聯刪除:cascade=delete
		LinkMan linkMan = session.get(LinkMan.class, 1l);
		session.delete(linkMan);
		
		transaction.commit();
	}

 

物件導航:

   前提是雙方都設定了cascade="save-update"


	/**
	 * 測試物件導航
	 * 		前提:一對多的雙方都設定cascade="sava-update"
	 */
	public void test5(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//一個客戶
		Customer customer1 = new Customer();
		customer1.setCust_name("1");
		
		//三個聯絡人
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("張三");
		LinkMan linkMan2 = new LinkMan();
		linkMan2.setLkm_name("李四");
		LinkMan linkMan3 = new LinkMan();
		linkMan3.setLkm_name("王如花");
		 
		//設定關係
		linkMan1.setCustomer(customer1);
		customer1.getLinkMans().add(linkMan2);
		customer1.getLinkMans().add(linkMan3);
		
		//雙方都設定了cascade
		//session.save(linkMan1);//4條insert語句
		//session.save(linkMan2);//1條insert語句
		session.save(customer1);//3條insert語句
		
		transaction.commit();
	}

 

inverse:

        比如將2號聯絡人從1號客戶改為2號客戶,原來會發三個select語句,兩個update語句,在Customer配置檔案中配置inverse="true",放棄外來鍵維護權,用來解決多餘的sql語句,這樣會只發送一條update語句,

    /**
	 * 將2號聯絡人原來歸1號客戶,現在在改為2號客戶
	 * 		
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//查詢2號聯絡人
		LinkMan linkMan = session.get(LinkMan.class, 2l);
		//查詢2號客戶
		Customer customer = session.get(Customer.class, 2l);
		
		//雙向關聯
		linkMan.setCustomer(customer);
		customer.getLinkMans().add(linkMan);
		
		transaction.commit();
	}

      區別:

           cascade管的是關聯物件,而inverse管的是一的一方控不控制外來鍵

 

多對多:

                    一個學生可以選擇多門課程,一門課程也可以被多個學生選擇。

                    一個使用者可以選擇多個角色,一個角色也可以被多個使用者選擇。

           建表原則:

                              建立一箇中間表,中間表至少有兩個欄位分別作為外來鍵指向多對多雙方的主鍵

                

               使用者和角色都是多

                建立實體類時:

                User類中有Role物件集合的屬性

                Role類中有USer物件集合的屬性

private Set<User> users = new HashSet<User>();
private Set<Role> roles = new HashSet<Role>();

           配置對映檔案時:

                這是Role的配置檔案,User的類似。

            <!-- 
    			set標籤
    				name:對方的集合的屬性名稱
    				table:多對多的關係需要使用中間表,放的是中間表的名稱
 		   	 -->
    		<set name="users" table="sys_user_role" >
    			<!-- 
    				key標籤:
    					column:當前物件所對應的外來鍵名稱
    			 -->
    			<key column="role_id"></key>
    			<!-- 
    				many-to-many標籤
    				class:對方的類的全路徑
    				column:對方的物件在中間表中的外來鍵名稱
    			 -->
    			<many-to-many class="domain.User" column="user_id"></many-to-many>
    		</set>

 

        多對多關係中如果進行了雙向維護關係(比如角色中新增使用者,使用者中新增角色),就必須有一方放棄外來鍵維護權,一般由被動方放棄

如下:

        如果不放棄外來鍵維護全,中間表中兩個欄位共同作為主鍵就會重複,報錯。

        所以在set中新增inverse=true

    public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//兩個使用者
		User user1 = new User();
		user1.setUser_name("u1");
		User user2 = new User();
		user2.setUser_name("u2");
		
		//三個角色
		Role role1 = new Role();
		role1.setRole_name("r1");
		Role role2 = new Role();
		role2.setRole_name("r2");
		Role role3 = new Role();
		role3.setRole_name("r3");
		
		//設定雙向關聯關係
		user1.getRoles().add(role1);
		user1.getRoles().add(role2);
		user2.getRoles().add(role3);
		user2.getRoles().add(role1);
		
		role1.getUsers().add(user1);
		role1.getUsers().add(user1);
		role2.getUsers().add(user2);
		role3.getUsers().add(user2);

		//儲存操作,多對多建立雙向關係時,必須有一方放棄外來鍵維護
		//一般是被動方放棄
		session.save(user1);
		session.save(user2);
		session.save(role1);
		session.save(role2);
		session.save(role3);
		
		transaction.commit();
	}

 

多對多級聯儲存(刪除類似):

    /**
	 * 多對多隻儲存一邊,會報瞬時物件異常
	 * 多對多的級聯,儲存使用者級聯角色,在使用者對映檔案中設定
	 * 		儲存角色級聯使用者,在角色對映檔案中設定
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//一個使用者
		User user1 = new User();
		user1.setUser_name("u1");
		
		
		//一個角色
		Role role1 = new Role();
		role1.setRole_name("r1");
		
		
		//設定雙向關聯關係
		user1.getRoles().add(role1);
		
		role1.getUsers().add(user1);
		
		session.save(user1);
		
		transaction.commit();
	}

多對多關係更多的是對集合的操作