表與表的關(guān)系
關(guān)鍵是維護(hù)關(guān)聯(lián)屬性
一對多|多對一
一對多(多對一):
- 數(shù)據(jù)表中:
客戶表
cid | cname |
---|---|
1 | 百度 |
2 | 網(wǎng)易 |
? 聯(lián)系人表
lid | lname | cid |
---|---|---|
1 | 張總 | 1 |
2 | 劉總 | 1 |
3 | 王總 | 2 |
-
實(shí)體中:
客戶(Cudtomer)實(shí)體:
private Long cid; private String cname; //使用集合表達(dá)‘一’的一方擁有多個‘多’的一方 private Set<LinkMan> linkMen;
聯(lián)系人(LinkMan)實(shí)體:
private Long lid; private String lname; //使用對象引用‘一’的一方表達(dá)‘多’的一方屬于哪個‘一’的一方 private Customer customer;
-
orm元數(shù)據(jù)中:
Customer.hbm.xml中(‘一’的一方):
<class name="Customer" table="cst_customer" > <id name="cust_id" > <generator class="native"></generator> </id> <property name="cust_name" column="cust_name" ></property> <property name="cust_source" column="cust_source" ></property> <property name="cust_industry" column="cust_industry" ></property> <property name="cust_level" column="cust_level" ></property> <property name="cust_linkman" column="cust_linkman" ></property> <property name="cust_phone" column="cust_phone" ></property> <property name="cust_mobile" column="cust_mobile" ></property> <!-- 集合,一對多關(guān)系,在配置文件中配置 --> <!-- name屬性:集合屬性名 column屬性: 外鍵列名 class屬性: 與我關(guān)聯(lián)的對象完整類名 --> <!-- 級聯(lián)操作: cascade save-update: 級聯(lián)保存更新 delete:級聯(lián)刪除 all:save-update+delete 級聯(lián)操作: 簡化操作.目的就是為了少些兩行代碼. --> <!-- inverse屬性: 配置關(guān)系是否維護(hù). true: customer不維護(hù)關(guān)系 false(默認(rèn)值): customer維護(hù)關(guān)系 inverse屬性: 性能優(yōu)化.提高關(guān)系維護(hù)的性能. 原則: 無論怎么放棄,總有一方必須要維護(hù)關(guān)系. 一對多關(guān)系中: 一的一方放棄.也只能一的一方放棄.多的一方不能放棄. --> <set name="linkMens" inverse="true" cascade="delete" > <key column="lkm_cust_id" ></key> <one-to-many class="LinkMan" /> </set> </class>
LinkMan.hbm.xml中(‘多’的一方):
<class name="LinkMan" table="cst_linkman" > <id name="lkm_id" > <generator class="native"></generator> </id> <property name="lkm_gender" ></property> <property name="lkm_name" ></property> <property name="lkm_phone" ></property> <property name="lkm_email" ></property> <property name="lkm_qq" ></property> <property name="lkm_mobile" ></property> <property name="lkm_memo" ></property> <property name="lkm_position" ></property> <!-- 多對一 --> <!-- name屬性:引用屬性名 column屬性: 外鍵列名 class屬性: 與我關(guān)聯(lián)的對象完整類名 --> <!-- 級聯(lián)操作: cascade save-update: 級聯(lián)保存更新 delete:級聯(lián)刪除 all:save-update+delete 級聯(lián)操作: 簡化操作.目的就是為了少些兩行代碼. --> <!-- 多的一方: 不能放棄維護(hù)關(guān)系的.外鍵字段就在多的一方. --> <many-to-one name="customer" column="lkm_cust_id" class="Customer" > </many-to-one> </class>
-
操作關(guān)聯(lián)屬性:
- 基本操作
//一對多|多對一關(guān)系操作 public class Demo { @Test //保存客戶 以及客戶 下的聯(lián)系人 public void fun1(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 Customer c = new Customer(); c.setCust_name("傳智播客"); LinkMan lm1 = new LinkMan(); lm1.setLkm_name("黎活明"); LinkMan lm2 = new LinkMan(); lm2.setLkm_name("劉悅東"); //表達(dá)一對多,客戶下有多個聯(lián)系人 c.getLinkMens().add(lm1); c.getLinkMens().add(lm2); //表達(dá)對對對,聯(lián)系人屬于哪個客戶 lm1.setCustomer(c); lm2.setCustomer(c); session.save(c); / session.save(lm1); / session.save(lm2); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } @Test //為客戶增加聯(lián)系人 public void fun2(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 //1> 獲得要操作的客戶對象 Customer c = session.get(Customer.class,1l); //2> 創(chuàng)建聯(lián)系人 LinkMan lm1 = new LinkMan(); lm1.setLkm_name("郝強(qiáng)勇"); //3> 將聯(lián)系人添加到客戶,將客戶設(shè)置到聯(lián)系人中 c.getLinkMens().add(lm1); lm1.setCustomer(c); //4> 執(zhí)行保存 session.save(lm1); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } @Test //為客戶刪除聯(lián)系人 public void fun3(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 //1> 獲得要操作的客戶對象 Customer c = session.get(Customer.class,1l); //2> 獲得要移除的聯(lián)系人 LinkMan lm = session.get(LinkMan.class, 3l); //3> 將聯(lián)系人從客戶集合中移除 c.getLinkMens().remove(lm); lm.setCustomer(null); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } }
-
進(jìn)階 - 級聯(lián)
cascade
屬性值:save-update
,不建議delete
級聯(lián)的效果只是簡化操作,可以少寫幾句代碼仆抵。
//測試級聯(lián)操作 public class Demo2 { @Test //保存客戶 以及客戶 下的聯(lián)系人 //cascade:save-update public void fun1(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 Customer c = new Customer(); c.setCust_name("傳智播客"); LinkMan lm1 = new LinkMan(); lm1.setLkm_name("黎活明"); LinkMan lm2 = new LinkMan(); lm2.setLkm_name("劉悅東"); //表達(dá)一對多,客戶下有多個聯(lián)系人 c.getLinkMens().add(lm1); c.getLinkMens().add(lm2); //表達(dá)對對對,聯(lián)系人屬于哪個客戶 lm1.setCustomer(c); lm2.setCustomer(c); session.save(c); // session.save(lm1); // session.save(lm2); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } @Test //測試刪除客戶時,級聯(lián)刪除客戶下的聯(lián)系人 //cascade:delete public void fun2(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 //1> 獲得要操作的客戶對象 Customer c = session.get(Customer.class,1l); //2>調(diào)用delete刪除客戶 session.delete(c); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } @Test //保存聯(lián)系人以及聯(lián)系人對應(yīng)的客戶 //cascade:save-update public void fun3(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 Customer c = new Customer(); c.setCust_name("北大青鳥"); LinkMan lm1 = new LinkMan(); lm1.setLkm_name("劉總"); //表達(dá)一對多,客戶下有多個聯(lián)系人 c.getLinkMens().add(lm1); //表達(dá)對對對,聯(lián)系人屬于哪個客戶 lm1.setCustomer(c); session.save(lm1); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } }
-
進(jìn)階 - 關(guān)系維護(hù)
優(yōu)化性能效率:在保存時.兩方都會維護(hù)外鍵關(guān)系.關(guān)系維護(hù)兩次,冗余了. 多余的維護(hù)關(guān)系語句,顯然是客戶這一端在維護(hù)關(guān)系。
inverse
屬性值true
時表示當(dāng)前配置的這一方放棄維護(hù)(字面意思反轉(zhuǎn)嘛)裙顽,默認(rèn)為false。
//操作進(jìn)階--關(guān)系維護(hù)屬性 public class Demo3 { @Test //保存客戶 以及客戶 下的聯(lián)系人 public void fun1(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 Customer c = new Customer(); c.setCust_name("傳智播客"); LinkMan lm1 = new LinkMan(); lm1.setLkm_name("黎活明"); LinkMan lm2 = new LinkMan(); lm2.setLkm_name("劉悅東"); //表達(dá)一對多,客戶下有多個聯(lián)系人. // 如果客戶放棄維護(hù)與聯(lián)系人的關(guān)系. 維護(hù)關(guān)系的代碼可以省略 //c.getLinkMens().add(lm1); //c.getLinkMens().add(lm2); //表達(dá)對對對,聯(lián)系人屬于哪個客戶 lm1.setCustomer(c); lm2.setCustomer(c); session.save(c); session.save(lm1); session.save(lm2); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } @Test //刪除客戶 public void fun2(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 Customer customer = session.get(Customer.class, 1l); session.delete(customer); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } }
多對多
數(shù)據(jù)表中:
員工表
uid | uname |
---|---|
1 | 張三 |
2 | 李四 |
3 | 王五 |
角色表
rid | rname |
---|---|
1 | 清潔工 |
2 | 總裁 |
3 | 前臺 |
員工角色表(采用中間表設(shè)計(jì)原則)
uid | rid |
---|---|
1 | 1 |
1 | 3 |
2 | 2 |
3 | 1 |
實(shí)體中:(使用集合來表達(dá)互相擁有多個對方)
員工(User)
private Long uid;
private String uname;
private Set<Role> roles;
角色(Role)
private Long rid;
private String rname;
private Set<User> users;
orm元數(shù)據(jù)中:
User.hbm.xml
<class name="User" table="sys_user" >
<id name="user_id" >
<generator class="native"></generator>
</id>
<property name="user_code" ></property>
<property name="user_name" ></property>
<property name="user_password" ></property>
<property name="user_state" ></property>
<!-- 多對多關(guān)系表達(dá) -->
<!--
name: 集合屬性名
table: 配置中間表名
key
|-column:外鍵,別人引用"我"的外鍵列名
class: 我與哪個類是多對多關(guān)系
column:外鍵.我引用比人的外鍵列名
-->
<!-- cascade級聯(lián)操作:
save-update: 級聯(lián)保存更新
delete:級聯(lián)刪除
all:級聯(lián)保存更新+級聯(lián)刪除
結(jié)論: cascade簡化代碼書寫.該屬性使不使用無所謂. 建議要用只用save-update.
如果使用delete操作太過危險.尤其在多對多中.不建議使用.
-->
<set name="roles" table="sys_user_role" cascade="save-update" >
<key column="user_id" ></key>
<many-to-many class="Role" column="role_id" ></many-to-many>
</set>
</class>
Role.hbm.xml
<class name="Role" table="sys_role" >
<id name="role_id" >
<generator class="native"></generator>
</id>
<property name="role_name" ></property>
<property name="role_memo" ></property>
<!-- 使用inverse屬性
true: 放棄維護(hù)外鍵關(guān)系
false(默認(rèn)值):維護(hù)關(guān)系
結(jié)論: 將來在開發(fā)中,如果遇到多對多關(guān)系.一定要選擇一方放棄維護(hù)關(guān)系.
一般誰來放棄要看業(yè)務(wù)方向. 例如錄入員工時,需要為員工指定所屬角色.
那么業(yè)務(wù)方向就是由員工維護(hù)角色. 角色不需要維護(hù)與員工關(guān)系.角色放棄維護(hù)
-->
<set name="users" table="sys_user_role" inverse="true" >
<key column="role_id" ></key>
<many-to-many class="User" column="user_id" ></many-to-many>
</set>
</class>
-
操作關(guān)聯(lián)屬性
基本操作
//多對多關(guān)系操作 public class Demo { @Test //保存員工以及角色 public void fun1(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 //1> 創(chuàng)建兩個 User User u1 = new User(); u1.setUser_name("郝強(qiáng)勇"); User u2 = new User(); u2.setUser_name("金家德"); //2> 創(chuàng)建兩個 Role Role r1 = new Role(); r1.setRole_name("保潔"); Role r2 = new Role(); r2.setRole_name("保安"); //3> 用戶表達(dá)關(guān)系 u1.getRoles().add(r1); u1.getRoles().add(r2); u2.getRoles().add(r1); u2.getRoles().add(r2); //4> 角色表達(dá)關(guān)系 r1.getUsers().add(u1); r1.getUsers().add(u2); r2.getUsers().add(u1); r2.getUsers().add(u2); //5> 調(diào)用Save方法一次保存 session.save(u1); session.save(u2); session.save(r1); session.save(r2); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } @Test //為郝強(qiáng)勇新增一個角色 public void fun3(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 //1> 獲得郝強(qiáng)勇用戶 User user = session.get(User.class, 1l); //2> 創(chuàng)建公關(guān)角色 Role r = new Role(); r.setRole_name("男公關(guān)"); //3> 將角色添加到用戶中 user.getRoles().add(r); //4> 將角色轉(zhuǎn)換為持久化 //session.save(r); //若在User.hbm.xml中配置了cascade屬性為save-update宣谈,則可以級聯(lián)保存愈犹,就不必寫上面這句代碼 //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } @Test //為郝強(qiáng)勇解除一個角色 public void fun4(){ //1 獲得session Session session = HibernateUtils.openSession(); //2 開啟事務(wù) Transaction tx = session.beginTransaction(); //------------------------------------------------- //3操作 //1> 獲得郝強(qiáng)勇用戶 User user = session.get(User.class, 1l); //2> 獲得要操作的角色對象(保潔,保安) Role r1 = session.get(Role.class, 1l); Role r2 = session.get(Role.class, 2l); //3> 將角色從用戶的角色集合中移除 user.getRoles().remove(r1); user.getRoles().remove(r2); //------------------------------------------------- //4提交事務(wù) tx.commit(); //5關(guān)閉資源 session.close(); } }
進(jìn)階 - inverse屬性:
使用inverse屬性 true: 放棄維護(hù)外鍵關(guān)系 false(默認(rèn)值):維護(hù)關(guān)系 結(jié)論: 將來在開發(fā)中,如果遇到多對多關(guān)系.一定要選擇一方放棄維護(hù)關(guān)系. 一般誰來放棄要看業(yè)務(wù)方向. 例如錄入員工時,需要為員工指定所屬角色. 那么業(yè)務(wù)方向就是由員工維護(hù)角色. 角色不需要維護(hù)與員工關(guān)系.角色放棄維護(hù)
進(jìn)階 - 級聯(lián)屬性
cascade級聯(lián)操作: save-update: 級聯(lián)保存更新 delete:級聯(lián)刪除 all:級聯(lián)保存更新+級聯(lián)刪除 結(jié)論: cascade簡化代碼書寫.該屬性使不使用無所謂. 建議要用只用save-update. 如果使用delete操作太過危險.尤其在多對多中.不建議使用.
?
?