一對多|多對一關係 ---- Hibernate之關聯對映
敘:hibernate中的關聯對映存在一對多多對一關係和多對多關係;本章節電蟲就關聯對映的一對多多對一關係進行學習和總結記錄;
Hibernate的關聯對映之“一對多|多對一”關係
準備工作
需要有兩個實體類以及實體類所對應的對映檔案,由於之前建立的有Customer類以及其對應的對映檔案,因此再建立一個實體類和其對映檔案就好了(下面的程式碼涉及到馬桑要學習的知識,即使看不懂可以先記著,下面會有詳細的講解記錄);
建立LinkMan類 這個是聯絡人類,這個類是客戶的聯絡人,也就是說一個客戶下有多個聯絡人,這個聯絡人類就是“一對多|多對一”關係中的哪個“多”的一方;
package com.java.domain;
public class LinkMan {
private Long lkm_id;
private Character lkm_gender;
private String lkm_name;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
//關聯對映的關聯類
private Customer customer;
:
:
:
// 省略的是類屬性的get/set方法的構建
}
對映檔案LinkMan.hbm.xml 對映檔案之前有詳細的介紹
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java.domain">
<!-- 建立類與表的對映 -->
<class name="LinkMan" table="cst_linkman">
<!-- 主鍵的配置 -->
<id name="lkm_id" column="lkm_id">
<generator class="native" />
</id>
<!-- 非主鍵屬性的配置 -->
<property name="lkm_gender" column="lkm_gender" ></property>
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_phone" column="lkm_phone"></property>
<property name="lkm_mobile" column="lkm_mobile"></property>
<property name="lkm_email" column="lkm_email"></property>
<property name="lkm_qq" column="lkm_qq"></property>
<property name="lkm_position" column="lkm_position"></property>
<property name="lkm_memo" column="lkm_memo"></property>
<!-- 多對一配置 -->
<many-to-one name="customer" column="lkm_cust_id" class="Customer">
</many-to-one>
</class>
</hibernate-mapping>
新知識點講解
根據程式碼說一下新增的知識點:
在建立的實體類中
LinkMan實體類中 在這個類中有一個
private Customer customer;
這個是建立一個關聯對映中關聯的類的物件,在這裡建立一個Customer類物件是為了在操作資料進行儲存聯絡人時能將關聯的客戶資訊儲存到聯絡人的資料表中;Customer實體類中 這個類並沒有寫出來,與原來的資料相比需要新增一個
private Set<LinkMan> linkMans = new HashSet<LinkMan>();
這個是在Customer類中建立一個聯絡人LinkMan類的物件,目的和LinkMan中新增Customer類的物件一樣; 分析: 其二者的書寫是由其所處的位置決定,LinkMan類是“一對多|多對一”關係中的“多”的一項,多個LinkMan才對應一個Customer,因此在LinkMan類中只要建立一個Customer類就好了,反過來,在Customer類中則需要建立的是一個集合,方便一個Customer對應多個LinkMan;
對映檔案配置分析
- LinkMan的對映檔案LinkMan.hbm.xml
<!-- 多對一配置 -->
<many-to-one name="customer" column="lkm_cust_id" class="Customer">
</many-to-one>
只有一個標籤<many-to-one>翻譯成中文就是“多對一”,關於對映檔案中的關聯對映的配置都在這類配置中了(有<one-to-one>、<many-to-one>、<many-to-many>、<one-to-many>),本章節我只學習了“多對一|一對多”關係,因此用到的只有<many-to-one>、<one-to-many>這兩種,下面就先對多對一的配置進行學習: 在標籤中有三個標籤,分別是:
屬性名 | 屬性值 | 解釋 |
---|---|---|
name | customer | LinkMan類中關聯的類在LinkMan類中建立的物件名 |
column | lkm_cust_id | 存放關聯物件相資訊的屬性名(在資料表中就是列名) |
class | Customer | LinkMan類所關聯的類的全類名(我只寫了類名,因為我在hibernate-mapping標籤中配置了package的值) |
Customer實體類的對映檔案配置
在Customer.hbm.xml中配置的程式碼如下所示:
<!-- 一對多配置 -->
<set name="linkMans">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
這一段就是配置關聯對映的配置; 總共有三個標籤,其中各有各自的屬性、屬性值,詳細介紹如下:
標籤名 | 屬性名 | 屬性值 | 解釋 |
---|---|---|---|
set | name | linkMans | Customer類中關聯的類在LinkMan類中建立的物件名(因為Customer類中建立的LinkMan類物件是用set集合建立的,因此要用set標籤進行配對) |
key | column | lkm_cust_id | Customer的主鍵作為外來鍵被LinkMan的哪個屬性(列)所引用; |
one-to-many | class | LinkMan | Customer類所關聯的類的全類名(我只寫了類名,因為我在hibernate-mapping標籤中配置了package的值) |
在核心配置檔案上進行配置
這個也就是在核心配置檔案中引入兩個類的ORM源路徑,如下圖所示:
測試
測試程式碼如下所示:
package com.java.demo;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.java.domain.Customer;
import com.java.domain.LinkMan;
import com.java.hibernate.Utils.HibernateUtils;
public class Demo1 {
@Test
public void demo1(){
// 1.使用工具類創建出session
Session session = HibernateUtils.openSession();
// 2.開啟事務
Transaction bt = session.beginTransaction();
// 3.分別建立Customer類、LinkMan類的物件並寫入資料
Customer c = new Customer();
c.setCust_name("喜羊羊與灰太狼");
LinkMan L1 = new LinkMan();
L1.setLkm_name("喜羊羊");
LinkMan L2 = new LinkMan();
L2.setLkm_name("美羊羊");
// 在Customer類物件中儲存其對應的聯絡人資訊
c.getLinkMans().add(L1);
c.getLinkMans().add(L2);
//在LinkMan類物件中儲存其對應的客戶資訊
L1.setCustomer(c);
L2.setCustomer(c);
session.save(c);
session.save(L1);
session.save(L2);
// 4.提交事務
bt.commit();
session.close();
}
}
注意:在此關聯對映中,需要關係宣告,這個宣告是需要兩方都進行的,程式碼就是下面的:
// 在Customer類物件中儲存其對應的聯絡人資訊 -- 一對多的插入關係(關係宣告)
c.getLinkMans().add(L1);
c.getLinkMans().add(L2);
//在LinkMan類物件中儲存其對應的客戶資訊 -- 多對一的插入關係(關係宣告)
L1.setCustomer(c);
L2.setCustomer(c);
執行@Test後資料庫中的對應的表中會出現對應的資料,如下圖所示: 客戶表中的資料: 聯絡人表中的資料:
重點看聯絡人表中的“lkm_cust_id”這列中的數值與客戶表中的新建立的資料的id是否一致;
進階操作
級聯操作
在進行操作時會發現在資料的save()方法儲存時存在缺陷,比如,新建一個客戶並且客戶下有N個聯絡人需要新增進去,那麼在進行session.save(“linkman1”);的操作時需要寫N次才行,因此,為了減少此程式碼的編寫量,有了級聯操作;
具體用法: 在客戶和聯絡人的ORM檔案中配置且配置一樣,具體配置如下
<set name="linkMans" inverse="true" cascade="save-update">
既是:在set標籤中新增一個cascade屬性; cascade:級聯屬性
屬性名 | 屬性值 | 解釋 |
---|---|---|
cascade | save-update | 配置此值是代表的是級聯儲存更新 |
cascade | delete | 配置此值是代表的是級聯刪除 |
cascade | all | 配置此值是代表的是以上兩種都包含 |
在LinkMan的對映問價中沒有set標籤,只有一個<many-to-one>標籤,因此直接寫在這個標籤中就好; 當配置完後無論從哪一方進行資料儲存時,另一方的亦可以被連帶儲存;
注意: 1) 在聯絡人進行級聯刪除時,必須要在客戶的對映檔案中配置級聯刪除的功能,不然會存在被級聯刪除的客戶下的聯絡人仍存在,這樣會照成資料垃圾; 2) 一般情況下使用的是save-update這個設定,目的是為了保護資料的安全性,防止被誤刪;
關係維護
在hibernate中關係的維護預設是一對多和多對一都要進行維護,這是沒有必要的,只要有一方進行維護就好,兩次的話雖然在這個關係中不會報錯,但是浪費資源,並且在多對多關係中會報錯(下一章節學習的),因此,我們可以使用inverse屬性進行設定是誰來維護; 配置維護方的屬性是inverse;其屬性值只有false、true這兩個,inverse譯為反轉,如果設定為true,意味著這個實體不負責進行維護關係,如果為false則是負責關係的為維護; 配置的位置和cascade配置位置一樣,如果在Customer類的ORM檔案中配置了此設定並將其屬性值配置為true的話,這就意味著Customer類並不負責關係維護,因此,預設的就是LinkMan類負責(在LinkMan類的對映檔案中不要再進行設定);一般情況下只需要一方負責,約定俗成的是由“多”的一方來負責維護; 另外,以上面的程式碼為例,Customer類代表的是客戶,客戶不負責對關係的維護後在程式碼的實際程式設計中也會有所體現,可以省略掉Customer的關係設定,只由LinkMan類來設定關係就好,具體如下所示:
pass:本章節的“一對多|多對一”關係學習就到這裡了,下章節會對“多對多”關係進行學習記錄;