Hibernate4實戰 之 第四部分:關係映射

數據表之間的關係分爲三類:一對1、一對多、多對多
一對一數據表(部門表  和  部門主管表)
一對多數據表(部門表  和  部門下的人員表)
多對多數據表(部門表  和  人員表)
 
根據相互尋找的關係又分:單向和雙向
對象一對一 (雙向

java代碼:
public class A {
private B b = null;  }
public class B {
private A a = null;  }
n對象一對多 (雙向)
public class A {
private B b = null;  }
public class B {
private Collection<A> colA = null;  }
n對象多對多 (雙向)
public class A {
private Collection<B> colB = null;  }
public class B {
private Collection<A> colA = null;  }
 
雙向一對可能是最經常使用的映射關係
<key>元素
<key> 元素在父映射元素定義了對新表的鏈接,而且在被鏈接表中定義了一個外鍵引用原表的主鍵的狀況下常用。

java代碼:
<key
column="columnname"(1)
on-delete="noaction|cascade"(2)
property-ref="propertyName"(3)
not-null="true|false"(4)
update="true|false"(5)
unique="true|false"(6)
/>
(1)column(可選):外鍵字段的名稱。也能夠經過嵌套的 <column> 指定。
(2)on-delete(可選,默認是 noaction):代表外鍵關聯是否打開數據庫級別的級聯刪除。
(3)property-ref(可選):代表外鍵引用的字段不是原表的主鍵(提供給遺留數據)。
(4)not-null(可選):代表外鍵的字段不可爲空,意味着不管什麼時候外鍵都是主鍵的一部分。
(5)update(可選):代表外鍵決不該該被更新,這意味着不管什麼時候外鍵都是主鍵的一部分。
(6)unique(可選):代表外鍵應有惟一性約束,這意味着不管什麼時候外鍵都是主鍵的一部分。
對那些看重刪除性能的系統,推薦全部的鍵都應該定義爲 on-delete="cascade",這樣Hibernate 將使用數據庫級的 ON CASCADE DELETE 約束,而不是多個 DELETE 語句用於映射集合類的
Hibernate映射元素取決於接口的類型。好比,<set>元素用來映射Set類型的屬性:

java代碼:
<class name="Product">
<id name="serialNumber" column="productSerialNumber"/>
<set name="parts">
<key column="productSerialNumber" not-null="true"/>
<one-to-many class="Part"/>
</set>
</class>
除了<set>,還有<list>, <map>, <bag>, <array> 和 <primitive-array> 映射元素。<map>具備表明性 ,以下:

java代碼:
<map
name="propertyName" (1)
table="table_name" (2)
schema="schema_name" (3)
lazy="true|extra|false" (4)
inverse="true|false" (5)
cascade=「all|none|save-update|delete|all-delete-orphan|delete-orphan」(6) sort="unsorted|natural|comparatorClass" (7)
order-by="column_name asc|desc" (8)
where="arbitrary sql where condition" (9)
fetch="join|select|subselect" (10)
batch-size="N" (11)
access="field|property|ClassName" (12)
optimistic-lock="true|false" (13)
mutable="true|false" (14)
>
<key .... /> <map-key .... />
<element .... />
</map>
(1) name 集合屬性的名稱
(2) table (可選——默認爲屬性的名稱)這個集合表的名稱(不能在一對多的關聯關係中使用)
(3) schema (可選) 表的schema的名稱, 他將覆蓋在根元素中定義的schema
(4) lazy (可選--默認爲true) 能夠用來關閉延遲加載(false),
(5) inverse (可選——默認爲false) 標記這個集合做爲雙向關聯關係中的方向一端。
(6) cascade (可選——默認爲none) 讓操做級聯到子實體
(7) sort(可選)指定集合的排序順序
(8) order-by (可選, 僅用於jdk1.4) 指定表的字段(一個或幾個)再加上asc或者desc(可選), 定義Map,Set和Bag的迭代順序
(9) where (可選) 指定任意的SQL where條件, 該條件將在從新載入或者刪除這個集合時使用(當集合中的數據僅僅是全部可用數據的一個子集時這個條件很是有用)
(10) fetch (可選, 默認爲select) 用於在外鏈接抓取、經過後續select抓取和經過後續subselect抓取之間選擇。
(11) batch-size (可選, 默認爲1) 指定經過延遲加載取得集合實例的批處理塊大小
(12) access(可選-默認爲屬性property):Hibernate取得集合屬性值時使用的策略
(13) 樂觀鎖 (可選 - 默認爲 true): 對集合的狀態的改變會是否致使其所屬的實體的版本增加。 (對一對多關聯來講,關閉這個屬性經常是有理的)
(14) mutable(可變) (可選 - 默認爲true): 若值爲false,代表集合中的元素不會改變(在某些狀況下能夠進行一些小的性能優化)。
集合外鍵
集合實例在數據庫中依靠持有集合的實體的外鍵加以辨別。此外鍵做爲集合關鍵字段加以引用。集合關鍵字段經過 <key> 元素映射。
在外鍵字段上可能具備非空約束。對於大多數集合來講,這是隱含的。對單向一對多關聯來講,外鍵字段默認是能夠爲空的,所以你可能須要指明 not-null=「true」。示例以下:

java代碼:
<key column="productSerialNumber" not-null="true"/>
外鍵約束可使用 ON DELETE CASCADE,示例以下:

java代碼:
<key column="productSerialNumber" on-delete="cascade"/>
one-to-one
經過 one-to-one 元素,能夠定義持久化類的一對一關聯。

java代碼:
<one-to-one
name="propertyName"(1)
class="ClassName"(2)
cascade="cascade_style"(3)
constrained="true|false"(4)
fetch="join|select"(5)
property-ref="propertyNameFromAssociatedClass"(6)
access="field|property|ClassName"(7)
formula="any SQL expression"(8)
lazy="proxy|no-proxy|false"(9)
entity-name="EntityName"(10)
/>
(1)name:屬性名。
(2)class(可選 — 默認是經過反射獲得的屬性類型):被關聯的類的名字。
(3)cascade(級聯)(可選)代表操做是否從父對象級聯到被關聯的對象。
(4)constrained(約束)(可選)代表該類對應的表對應的數據庫表,和被關聯的對象所對應的數據庫表之間,經過一個外鍵引用對主鍵進行約束。這個選項影響 save() 和 delete() 在級聯執行時的前後順序以及決定該關聯可否被委託(也在 schema export tool 中被使用)。
(5)fetch(可選 — 默認爲 select):在外鏈接抓取(outer-join fetching)和序列選擇抓取(sequential select fetching)二者中選擇其一。
(6)property-ref:(可選)指定關聯類的屬性名,這個屬性將會和本類的主鍵相對應。若是沒有指定,會使用對方關聯類的主鍵。
(7)access(可選 — 默認爲 property):Hibernate 用來訪問屬性值的策略。
(8)formula (可選):絕大多數一對一的關聯都指向其實體的主鍵。在一些少見的狀況中,你可能會指向其餘的一個或多個字段,或者是一個表達式,這些狀況下,你能夠用一個 SQL 公式來表示。(能夠在 org.hibernate.test.onetooneformula 找到例子)
(9)lazy(可選 — 默認爲 proxy):默認狀況下,單點關聯是通過代理的。lazy="no-proxy"指定此屬性應該在實例變量第一次被訪問時應該延遲抓取(fetche lazily)(須要運行時字節碼的加強)。 lazy="false"指定此關聯老是被預先抓取。注意,若是constrained="false", 不可能使用代理,Hibernate會採起預先抓取。
(10)entity-name(可選):被關聯的類的實體名。
nmany-to-one
經過 many-to-one 元素,能夠定義一種常見的與另外一個持久化類的多對一關聯,這個表的一個外鍵引用目標表的主鍵字段。

java代碼:
<many-to-one
name="propertyName" (1)
column="column_name" (2) 
class="ClassName" (3)
cascade="cascade_style"(4)
fetch="join|select" (5)
update="true|false" (6)
insert="true|false" (7)
property-ref="propertyNameFromAssociatedClass"(8)
access="field|property|ClassName"(9)
unique="true|false" (10)
not-null="true|false" (11)
optimistic-lock="true|false「 (12)
lazy="proxy|no-proxy|false" (13)
not-found="ignore|exception「 (14)
entity-name="EntityName" (15)
formula="arbitrary SQL expression"(16)
/>
(1)name:屬性名。
(2)column(可選):外鍵字段的名稱。也能夠經過嵌套的 <column> 指定。
(3)class(可選 — 默認是經過反射獲得的屬性類型):被關聯的類的名字。
(4)cascade(級聯)(可選)代表操做是否從父對象級聯到被關聯的對象。
(5)fetch(可選 — 默認爲 select):在外鏈接抓取和序列選擇抓取二者中選擇其一。
(6)update, insert(可選 — 默認爲 true)指定對應的字段是否包含在用於 UPDATE 和/或 INSERT的 SQL 語句中。若是兩者都是false,則這是一個純粹的 「外源性(derived)」關聯,它的值是經過
 映射到同一個(或多個)字段的某些其餘屬性獲得 或者經過 trigger(觸發器)、或其餘程序生成。
(7)property-ref:(可選)被關聯到此外鍵的類中的對應屬性的名字。若是不指定,使用被關聯類的主鍵
(8)access(可選 — 默認爲 property):Hibernate 用來訪問屬性值的策略。
(9)unique(可選):使用 DDL 爲外鍵字段生成一個惟一約束。此外, 這也能夠用做 propertyref的目標屬性。這使關聯同時具備一對一的效果。
(10)not-null(可選):使用 DDL 爲外鍵字段生成一個非空約束。
(11)optimistic-lock(可選 — 默認爲 true):指定這個屬性在作更新時是否須要得到樂觀鎖定。換句話說,它決定這個屬性發生髒數據時版本(version)的值是否增加。
(12)lazy(可選 — 默認爲 proxy):默認狀況下,單點關聯是通過代理的。lazy="no-proxy" 指定此屬性應該在實例變量第一次被訪問時應該延遲抓取(fetche lazily)(須要運行時字節碼的加強)。lazy="false" 指定此關聯老是被預先抓取。
(13)not-found(可選 - 默認爲exception):指定如何處理引用缺失行的外鍵:ignore 會把缺失的行做爲一個空關聯處理。
(14)entity-name(可選):被關聯的類的實體名。
(15)formula(可選):SQL 表達式,用於定義 computed(計算出的)外鍵值。
 
one-to-many
經過 one-to-many 元素,能夠定義一種常見的與另外一個持久化類的一對多關聯。

java代碼:
<one-to-many
class="ClassName"(1)
not-found="ignore|exception"(2)
entity-name="EntityName"(3)
/>
(1)class(必需):被關聯類的名稱。
 
(2)not-found(可選 - 默認爲exception):指明若緩存的標示值關聯的行缺失,該如何處理:ignore 會把缺失的行做爲一個空關聯處理。
 
(3)entity-name(可選):被關聯的類的實體名,做爲 class 的替代。
 
注意:<one-to-many> 元素不須要定義任何字段。也不須要指定表名。
仍是用示例來看,下面做一個雙向一對多的關係示例:
1:新建一個Parent對象和Child對象,Parent對象裏面有一個Child對象的集合,Child對象裏面有一個對Parent對象的引用,以下:

java代碼:
public class Parent{
  private String id;
  private String name;
  private Set children = new HashSet();
……
}
public class Child {
  private String uuid;
  private String address;
  private String postCode;
  private Parent parent;
……
}
Parent.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.javass.h3.parentchild.Parent" table="tbl_parent" dynamic-update="true" dynamic-insert="true" lazy="true">
        <id name="id" column="uuid" type="java.lang.String" unsaved-value="any">
            <generator class="assigned"> </generator>
        </id>
        <property name="name"  update="true" insert="true"/>       
<set name="children" inverse="true"  cascade="all">
<key column="tbl_parent_fk"/>
<one-to-many class="cn.javass.h3.parentchild.Child"/>
</set>
    </class>
</hibernate-mapping>
 
Child.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.javass.h3.parentchild.Child" table="tbl_child" dynamic-update="true" dynamic-insert="true" lazy="true">
        <id name="uuid" column="uuid" type="java.lang.String" unsaved-value="any">
            <generator class="assigned"> </generator>
        </id>
        <property name="address"  update="true" insert="true"/>
<property name="postCode"  update="true" insert="true"/>
<many-to-one
name="parent"
column="tbl_Parent_fk"
class="cn.javass.h3.parentchild.Parent"
not-null="true"
/>
    </class>
</hibernate-mapping>
客戶端測試TestMR.java文件太長,直接看演示好了。
在這個測試裏面分別演示了單獨的操做和級聯的操做。
inverse:指定由哪一方來維護雙方的關聯關係,默認是false,也就是雙方都維護,主要用在一對多 和 多對多中。
在一對多中使用inverse的時候,一般是在」一」這一端設置inverse=true,他的意思就是由多的那一端去維護關係,非反向端用於把內存中的表示保存到數據庫中。以下:
Parent p = new Parent();
Child c = new Child();
c.setParent(p); //維護父子之間關係
p.getChildren().add(c);
ninverse還有一個重要特色就是會優化Sql
ncascade:定義對象的級聯關係
all : 全部狀況下均進行關聯操做
none:全部狀況下均不進行關聯操做。這是默認值
save-update:在執行save/update/saveOrUpdate時進行關聯操做
delete:在執行delete時進行關聯操做
簡單的示範一下雙向的一對一
雙向一對一的操做是相似於雙向一對多的,只是配置上有一些不一樣:
1:Parent裏面的配置,示例以下:
<one-to-one name=  「cc」 class=  「cn.javass.h3.parentchild.Child」cascade=  「all」  property-ref=  「parent「/>這裏的property-ref參照的是Child對象裏面的屬性。
2:Child裏面的配置,不是使用one-to-one,而是仍使用many-to-one,示例以下:
<many-to-one name=「parent」 class=「cn.javass.h3.parentchild.Parent」 column=「tbl_parent_fk」/>
3:測試程序裏面,原來調用集合的地方,變成調用一個Child對象,其餘就差很少了,能夠測試看看。
 
Hibernate4的過濾器
Hibernate3 新增了對某個類或者集合使用預先定義的過濾器條件(filter criteria)的功能。過濾器條件至關於定義一個 很是相似於類和各類集合上的「where」屬性的約束子句,  可是過濾器條件能夠帶參數,應用程序能夠在運行時決  定是否啓用給定的過濾器,以及使用什麼樣的參數值。過濾器的用法很像數據庫視圖,只不過是在應用程序中肯定使用什麼樣的參數的。
 
定義過濾器
要使用過濾器,首先要在相應的映射節點中定義。而定義一個過濾器,要用到位於 <hibernatemapping/>節點以內的 <filter-def/> 節點:
示例以下:

java代碼:
<filter-def name="myFilter">
<filter-param name="myFilterParam" type="string"/>
</filter-def>
 
使用過濾器之配置
定義好以後,就能夠在某個類中使用這個過濾器:

java代碼:
<class name="myClass" ...>
...
<filter name="myFilter" condition=":myFilterParam=FILTERED_COLUMN"/>
</class>
或者也能夠在某個集合使用它:

java代碼:
<set ...>
<filter name="myFilter" condition=":myFilterParam=FILTERED_COLUMN"/>
</set>
 
在同時可使用多個過濾器。
使用過濾器之程序
在程序中,須要使用session接口中的:enableFilter(String filterName),getEnabledFilter(String filterName),和 disableFilter(String filterName)方法。Session中默認不啓用過濾器,必須經過enabledFilter() 方法顯式的啓用。
示例代碼session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");
過濾器示例
在Parent.hbm.xml中定義有以下的過濾器:

java代碼:
<filter-def name="myFilter">
<filter-param name="myFilterParam" type="string"/>
</filter-def>
<filter-def name="myFilter2">
<filter-param name="myFilterParam" type="int"/>
<filter-param name="myFilterParam2" type="int"/>
</filter-def>
在定義Child集合中使用

java代碼:
<set name="children" inverse="true" cascade="all" fetch="select" lazy="false" batch-size="3">
<key column="tbl_parent_fk"/>
<one-to-many class="cn.javass.h3.parentchild.Child" />
<filter name="myFilter"
condition="address like :myFilterParam"></filter>
<filter name="myFilter2" condition="uuid &gt;= :myFilterParam and uuid &lt;= :myFilterParam2"></filter>
</set>
程序中使用示例

java代碼:
s.enableFilter("myFilter").setParameter("myFilterParam", "%1%");
s.enableFilter("myFilter2").setParameter("myFilterParam", 1)
.setParameter("myFilterParam2", 3);
Query q = s.createQuery("select p from Parent as p  ");
System.out.println("p==="+p.getChildren());
視頻配套PPT,視頻地址【  Hibernate4實戰-獨家視頻課程 
原創內容 轉自請註明【 http://sishuok.com/forum/blogPost/list/2479.html#7154
相關文章
相關標籤/搜索