當類與類之間建立了關聯,就可以方便的從一個對象導航到另一個對象。或者通過集合導航到一組對象。例如:
對于給定的Emp對象,如果想獲得與它關聯的Dept對象,只要調用如下方法
Dept dept=emp.getDept(); //從Emp對象導航到關聯的Dept對象
以Dept(部門)類和Emp(員工)類為例:
一、配置雙向一對多關聯
需在Dept類中增加一個集合類型的emps屬性
private Set<Emp> emps=new HashSet<Emp>(); public Set<Emp> getEmps() { return emps; } public void setEmps(Set<Emp> emps) { this.emps = emps;
如何在映射文件中映射集合類型的emps屬性。由于在Dept表中沒有直接與emps屬性對應的字段。因此不能用<property>元素來映射emps屬性,而要使用<set>元素:
<set name="emps">
<key column="deptNo"></key> <!-- 多的一方 emp外鍵 -->
<one-to-many class="Emp" />
</set>
解析:
<set>元素的name屬性:設定持久化類的屬性名。此處為Dept類的emps屬性。
<set>元素還包含兩個子元素:
①<key>元素:column屬性設定與所關聯的持久化類對應的表的外鍵
②<one-to-many>元素:class屬性設定與所關聯的持久化類
hibernate根據以上映射代碼獲得以下信息:
①<set>元素表明Dept類的emps屬性為java.util.Set集合類型
②<one-to-many>子元素表明emps集合中存放的是一組Emp對象
③<key>子元素表明EMP表通過外鍵DEPTNO參照Dept表
Dept.hbm.xml代碼:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.happy.onetomanydouble"> <class name="Dept" table="DEPT"> <id name="deptNo"> <generator class="sequence"> <param name="sequence">SEQ_NUM</param> </generator> </id> <property name="deptName"/> <!-- 一對多一個配置,一個部門有N個員工 --> <!-- inverse="false" 主動方 維護關聯關系 inverse="true" 不維護關聯關系(不干擾Emp的外鍵生成) --> <set name="emps" cascade="save-update"> <key column="deptNo"></key> <!-- 多的一方 emp外鍵 --> <one-to-many class="Emp" /> </set> </class> </hibernate-mapping>
Emp.hbm.xml:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.happy.onetomanydouble"> <class name="Emp" table="EMP"> <id name="empId"> <generator class="sequence"> <param name="sequence">SEQ_NUM</param> </generator> </id> <property name="empName" type="string"/> <!-- 植入一個Dept對象 : 多對一--> <many-to-one name="dept" class="Dept" column="deptNo"></many-to-one> </class> </hibernate-mapping>
進而編寫測試類:Test 即可拿到deptNo為1的員工姓名
public class Test2 { Session session; Transaction tx; @After public void afterTest(){ tx.commit(); HibernateUtil.CloseSession(); } @Before public void initData(){ session=HibernateUtil.getSession(); tx=session.beginTransaction(); } /* * 一對多雙向關聯測試 */ @Test public void oneToManyDoubleTest(){ //獲取員工集合 Dept dept=(Dept)session.load(Dept.class,1); Set<Emp> emps =dept.getEmps(); for (Emp emp : emps) { System.out.println(emp.getEmpName()); } }
二、cascade屬性
none:當Session操縱當前對象時,忽略其他關聯的對象。它是cascade屬性的默認值.
Save-update:當通過Session的save()、update()及saveOrUpdate()方法來保存或更新當前對象時,級聯保存所有關聯的新建的瞬時狀態的對象,并且級聯更新所有關聯的游離狀態的對象。
Delete:當通過Session的delete()方法刪除當前對象時,會級聯刪除所有關聯的對象。
當通過Session的delete()方法刪除當前對象時,會級聯刪除所有關聯的對象。
All:包含save-update,delete的行為。
解析:
級聯也就是說當我們保存持久化對象A的時候自動幫我們保存持久化對象B。
問題:cascade屬性寫在什么位置?
注:一對一或者多對一的時候,直接寫在標簽上,其他的寫在set標簽上。
如何實現添加部門的同時自動添加員工?
解析:可以使用cascade(級聯)方式
Test:雙向關聯 通過add()將新建的員工對象添加部門下
public class Test3 { Session session; Transaction tx; @After public void afterTest(){ tx.commit(); HibernateUtil.CloseSession(); } @Before public void initData(){ session=HibernateUtil.getSession(); tx=session.beginTransaction(); } /* *cascade */ @Test public void oneTest(){ //構建一個部門 Dept dept=new Dept(); dept.setDeptName("財務部"); //構建一個員工 Emp emp=new Emp(); emp.setEmpName("張三"); //指定員工隸屬的部門 emp.setDept(dept); // setXXX 部門下的員工 dept.getEmps().add(emp); //save session.save(dept); session.save(emp); } }
三、<Set>元素下的inverse屬性(反轉)
inverse屬性指定了關聯關系中的方向。
inverse設置為false,則為主動方,由主動方負責維護關聯關系,默認是false 。
注意:inverse 決定是否把對對象中集合的改動反映到數據庫中,所以inverse只對集合起作用,也就是只對one-to-many或many-to-many有效(因為只有這兩種關聯關系包含集合,而one-to-one和many-to-one只含有關系對方的一個引用)。
代碼同理:
說明:如果我既給員工指定了自己所屬的部門,又將員工添加到部門集合中。那么這個時候reverse不設置,生成以下sql
inverse設置為true,不負責維護關聯關系
第二條insert語句已經在員工表中指定了自己所屬的部分,沒有必要再向數據庫發送一條update指令。
將inverse設置成true后,生成的語句如下圖所示。
文章列表