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();
}
多對多關係更多的是對集合的操作