Hibernate深入理解----05關聯關系(一對一,多對多)
來源:程序員人生 發布時間:2016-09-26 08:37:18 閱讀次數:2532次
參考代碼下載github:https://github.com/changwensir/java-ee/tree/master/hibernate4
1、1對1

public class Manager{
private Integer mgrId;
private String mgrName;
private Department dept;
//省去get,set方法
}
public class Department {
private Integer deptId;
private String deptName;
private Manager mgr; //這個是外鍵,對應表的manager_id
//省去get,set方法
}
1⑴.基于外鍵映照的 1⑴
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.oneToOne.pojo">
<class name="Department" table="DEPARTMENTS">
<id name="deptId" type="java.lang.Integer">
<column name="DEPT_ID" />
<generator class="native" />
</id>
<property name="deptName" type="java.lang.String">
<column name="DEPT_NAME" />
</property>
<!-- 使用 many-to-one 的方式來映照 1⑴ 關聯關系, 會在這個表里生成1個外鍵-->
<many-to-one name="mgr" class="Manager"
column="MGR_ID" unique="true"/>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.oneToOne.pojo">
<class name="Manager" table="MANAGERS">
<id name="mgrId" type="java.lang.Integer">
<column name="MGR_ID" />
<generator class="native" />
</id>
<property name="mgrName" type="java.lang.String">
<column name="MGR_NAME" />
</property>
<!-- 映照 1⑴ 的關聯關系: 在對應的數據表中已有外鍵了, 當前持久化類使用 one-to-one 進行映照 -->
<!--
沒有外鍵的1端需要使用one-to-one元素,該元素使用 property-ref 屬性指定使用被關聯實體主鍵之外的字段作為關聯字段
-->
<one-to-one name="dept" class="Department" property-ref="mgr"/>
</class>
</hibernate-mapping>
兩個hbm.xml文件要配置到cfg.xml里
測試方法
@Test
public void testSave(){
Department department = new Department();
department.setDeptName("DEPT-BB");
Manager manager = new Manager();
manager.setMgrName("MGR-BB");
//設定關聯關系
department.setMgr(manager);
manager.setDept(department);
//保存操作
//建議先保存沒有外鍵列的那個對象. 這樣會減少 UPDATE 語句
session.save(manager);
session.save(department);
}
@Test
public void testGet(){
//1. 默許情況下對關聯屬性使用懶加載(由于沒有把關聯的Manager查找出來)
Department dept = (Department) session.get(Department.class, 13);
System.out.println(dept.getDeptName());
//2. 所以會出現懶加載異常的問題.
// sessionPojo.close(); //還有把destory()方法里的session 和transaction注解掉
// Manager mgr = dept.getMgr();
// System.out.println(mgr.getClass());
// System.out.println(mgr.getMgrName());
//3. 查詢 Manager 對象的連接條件應當是 dept.manager_id(外鍵字段) = mgr.manager_id
// 而不應當是 dept.dept_id = mgr.manager_id。
//這里需要在Manager.hbm.xml里設置property-ref!!!
Manager mgr = dept.getMgr();
System.out.println(mgr.getMgrName());
}
/**
* 基于外鍵映照的 1⑴
* 對基于外鍵的1⑴關聯,其外鍵可以寄存在任意1邊,在需要寄存外鍵1端,增加many-to-one元素。
* 為many-to-one元素增加unique=“true” 屬性來表示為1⑴關聯
* 另外一端需要使用one-to-one元素,該元素使用 property-ref 屬性指定使用被關聯實體主鍵之外的字段作為關聯字段
*/
@Test
public void testGet2(){
//在查詢沒有外鍵的實體對象時, 使用的左外連接查詢, 1并查詢出其關聯的對象
//并已進行初始化.
Manager mgr = (Manager) session.get(Manager.class, 13);
System.out.println(mgr.getMgrName());
System.out.println(mgr.getDept().getDeptName());
}
1⑵.基于主鍵映照的 1⑴
基于主鍵的映照策略:指1真個主鍵生成器使用 foreign 策略,表明根據”對方”的主鍵來生成自己的主鍵,自己其實不能獨立生成主鍵. <param> 子元素指定使用當前持久化類的哪一個屬性作為 “對方”
采取foreign主鍵生成器策略的1端增加 one-to-one 元素映照關聯屬性,其one-to-one屬性還應增加 constrained=“true” 屬性;另外一端增加one-to-one元素映照關聯屬性。
constrained(束縛):指定為當前持久化類對應的數據庫表的主鍵添加1個外鍵束縛,援用被關聯的對象(“對方”)所對應的數據庫表主鍵
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.oneToOne.pojo">
<class name="Department" table="DEPARTMENTS">
<id name="deptId" type="java.lang.Integer">
<column name="DEPT_ID" />
<!-- 使用外鍵的方式來生成當前的主鍵!!!! -->
<generator class="foreign">
<!-- property 屬性指定使用當前持久化類的哪個屬性的主鍵作為外鍵 -->
<param name="property">mgr</param>
</generator>
</id>
<property name="deptName" type="java.lang.String">
<column name="DEPT_NAME" />
</property>
<!--基于外鍵改成基于主鍵:這里將many-to-one修改成one-to-one-->
<one-to-one name="mgr" class="Manager" constrained="true"/>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.oneToOne.pojo">
<class name="Manager" table="MANAGERS">
<id name="mgrId" type="java.lang.Integer">
<column name="MGR_ID" />
<generator class="native" />
</id>
<property name="mgrName" type="java.lang.String">
<column name="MGR_NAME" />
</property>
<!-- 映照 1⑴ 的關聯關系: 在對應的數據表中已有外鍵了, 當前持久化類使用 one-to-one 進行映照 -->
<one-to-one name="dept" class="Department"/>
</class>
</hibernate-mapping>
save方法,先插入哪一個都不會有過剩的update語句
@Test
public void testGet2(){
//在查詢沒有外鍵的實體對象時, 使用的左外連接查詢, 1并查詢出其關聯的對象
//并已進行初始化.
Manager mgr = (Manager) session.get(Manager.class, 1);
System.out.println(mgr.getMgrName());
System.out.println(mgr.getDept().getDeptName());
}
@Test
public void testGet(){
//1. 默許情況下對關聯屬性使用懶加載
Department dept = (Department) session.get(Department.class, 1);
System.out.println(dept.getDeptName());
//2. 所以會出現懶加載異常的問題.
Manager mgr = dept.getMgr();
System.out.println(mgr.getMgrName());
}
2、多對多


2⑴.單向/雙向n-n
n-n 的關聯必須使用連接表
與 1-n 映照類似,必須為 set 集合元素添加 key 子元素,指定 CATEGORIES_ITEMS 表中參照 CATEGORIES 表的外鍵為 CATEGORIY_ID. 與 1-n 關聯映照不同的是,建立 n-n 關聯時, 集合中的元素使用 many-to-many. many-to-many 子元素的 class 屬性指定 items 集合中寄存的是 Item 對象, column 屬性指定 CATEGORIES_ITEMS 表中參照 ITEMS 表的外鍵為 ITEM_ID
- 雙向 n-n 關聯需要兩端都使用集合屬性
- 雙向n-n關聯必須使用連接表
- 集合屬性應增加 key 子元素用以映照外鍵列, 集合元素里還應增加many-to-many子元素關聯實體類
- 在雙向 n-n 關聯的兩邊都需指定連接表的表名及外鍵列的列名. 兩個集合元素 set 的 table 元素的值必須指定,而且必須相同。set元素的兩個子元素:key 和 many-to-many 都必須指定 column 屬性,其中,key 和 many-to-many 分別指定本持久化類和關聯類在連接表中的外鍵列名,因此兩邊的 key 與 many-to-many 的column屬性交叉相同。也就是說,1邊的set元素的key的
cloumn值為a,many-to-many 的 column 為b;則另外一邊的 set 元素的 key 的 column 值 b,many-to-many的 column 值為 a.
對雙向 n-n 關聯, 必須把其中1真個 inverse 設置為 true, 否則兩端都保護關聯關系可能會造成主鍵沖突.
多個category對應多個item
public class Category {
private Integer id;
private String name;
private Set<Item> items = new HashSet<Item>();
//省去get,set方法
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.manyToMany">
<class name="Category" table="CATEGORIES">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<!-- table: 指定中間表 ,還可以增加cascade="save-update"-->
<set name="items" table="CATEGORIES_ITEMS">
<key>
<column name="C_ID" />
</key>
<!-- 使用 many-to-many 指定多對多的關聯關系. column 履行 Set 集合中的持久化類在中間表的外鍵列的名稱 -->
<many-to-many class="Item" column="I_ID"/>
</set>
</class>
</hibernate-mapping>
Item類
public class Item {
private Integer id;
private String name;
private Set<Category> categories = new HashSet<Category>();
//省去get,set方法
}
如果是單向n-n,則把下面那個雙向的配置去除就行
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.manyToMany">
<class name="Item" table="ITEMS">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<!-- 雙向n-n,則要加上這個:
table: 指定中間表 -->
<set name="categories" table="CATEGORIES_ITEMS" inverse="true">
<key column="I_ID"/>
<many-to-many class="Category" column="C_ID"/>
</set>
</class>
</hibernate-mapping>
測試類
@Test
public void testSave(){
Category category1 = new Category();
category1.setName("C-AA");
Category category2 = new Category();
category2.setName("C-BB");
Item item1 = new Item();
item1.setName("I-AA");
Item item2 = new Item();
item2.setName("I-BB");
//設定關聯關系
category1.getItems().add(item1);
category1.getItems().add(item2);
category2.getItems().add(item1);
category2.getItems().add(item2);
item1.getCategories().add(category1);
item1.getCategories().add(category2);
item2.getCategories().add(category1);
item2.getCategories().add(category2);
//履行保存操作
session.save(category1);
session.save(category2);
session.save(item1);
session.save(item2);
}
@Test
public void testGet(){
Category category = (Category) session.get(Category.class, 1);
System.out.println(category.getName());
//需要連接中間表
Set<Item> items = category.getItems();
System.out.println(items.size());
}
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈