4.1 簡單的POJO例子 我們將會(huì)在下面的章節(jié)中詳細(xì)的描述持久化類的四個(gè)重要規(guī)則 4.1.1實(shí)現(xiàn)一個(gè)無參構(gòu)造方法 Cat 類有一個(gè)無參的構(gòu)造方法。所以的持久化類必須有一個(gè)默認(rèn)的構(gòu)造器(可以不是public的)因此,Hibernate可以通過反射(java.lang.reflect.Constructor.newInstance())來實(shí)例化他們。 推薦定義這個(gè)構(gòu)造器的可見性至少為package 以便讓運(yùn)行時(shí)代理能夠正常的工作。 4.1.2 提供一個(gè)唯一標(biāo)示屬性 注意:這個(gè)是推薦的,但是到現(xiàn)在都沒有強(qiáng)制要求。這一條將會(huì)棄用,因?yàn)樵趯淼陌姹局袑?huì)強(qiáng)制要求提供一個(gè)唯一標(biāo)示屬性。Cat 有一個(gè)id屬性。 這個(gè)屬性對(duì)應(yīng)底層數(shù)據(jù)庫重的主鍵列。 唯一標(biāo)示的數(shù)據(jù)類型可以是任意的“基本”數(shù)據(jù)類型。 更多的復(fù)合主鍵參照9.4 聯(lián)合標(biāo)示主鍵。 注意:不需要在數(shù)據(jù)表中單獨(dú)為主鍵創(chuàng)建一個(gè)列, 他們只要是可以唯一的標(biāo)示這行數(shù)據(jù)在基本表中的唯一性即可。 我們推薦在持久化類中使用命名一致的標(biāo)示屬性, 可以把它定義為一個(gè)可以為Null的類型(例如, 非原始數(shù)據(jù)類型) 4.1.3推薦使用非final的類(可選) Hibernate的一個(gè)重要的特性 ,代理(懶加載),依賴于非final的或者是一些實(shí)現(xiàn)了最只定義了public方法的接口的持久化類。你可以使用hibernate持久化一個(gè)沒有繼承任何借口的類,但是這就導(dǎo)致你不能使用延遲關(guān)聯(lián)抓取的代理,這最終會(huì)限制了你在性能調(diào)優(yōu)方面的選擇。如果要持久化一個(gè)只實(shí)現(xiàn)了一個(gè)接口部分方法的類, 你必須禁用代理生成。參考示例4.2, 4.3 Example 4.2 通過hbm.xml 禁用代理應(yīng)該避免聲明public final 方法, 否則將會(huì)限制你使用該類來產(chǎn)生代理。如果你想要使用一個(gè)帶有public final方法的類, 你必須明確的禁止使用代理。 參考示例4.2 和4.3。
4.1.4 為持久化字段聲明函數(shù)(可選) Cat 類為他的每一個(gè)持久化字段都聲明了存取方法。 許多其他的ORM工具直接持久化實(shí)例變量。 比較好的做法是在關(guān)系模式和類的內(nèi)部數(shù)據(jù)結(jié)構(gòu)之間提供一個(gè)橋梁。默認(rèn)情況下, Hibernate 持久化JavaBean 識(shí)別格式為getFoo, isFoo和setFoo 的方法和屬性。 如果有需要, 一些特別的屬性你可以直接訪問字段。 屬性字段不需要一定是public的。Hibernate可以一樣持久化可見性為package,protected, 或者private的字段。4.2 實(shí)現(xiàn)繼承 一個(gè)子類也必須遵守第一和第二規(guī)則。它從父類繼承唯一標(biāo)示屬性。 如Cat.package eg;
public class DomesticCat extends Cat {
private String name;
public String getName() {
return name;
}
protected void setName(String name) {
this.name=name;
}
} 4.3 實(shí)現(xiàn)equals() 和hashCode() 意圖把持久化類的實(shí)例存放在Set中(描述多值關(guān)聯(lián)的推薦的方式); 并且 意圖使用游離的實(shí)例。Hibernate只在特定的session范圍保證持久化身份和Java身份的一致性。當(dāng)你在不同的session中混合檢索實(shí)例,如果你希望保證Sets是有意義的,那么你必須實(shí)現(xiàn)equals()和hashCode()方法。 最簡單的方法是實(shí)現(xiàn)equals()和hashCode()方法來比較來比較兩個(gè)對(duì)象間的標(biāo)示符的值。如果值相同,那么這兩個(gè)對(duì)象在一定在數(shù)據(jù)庫中對(duì)應(yīng)相同的數(shù)據(jù)行, 因?yàn)樗麄兪窍嗤摹?如果兩個(gè)都加入了Set集合,那么set集合中只會(huì)包含一個(gè)實(shí)例。不幸的是,對(duì)于自動(dòng)生成的標(biāo)示符不可以使用這種方法,因?yàn)镠ibernate只會(huì)為持久化的對(duì)象分配標(biāo)示符, 對(duì)于一個(gè)新產(chǎn)生的實(shí)例不會(huì)包含標(biāo)示符值。如果equals()和hashCode()基于標(biāo)示符,哈希碼將會(huì)改變, 打破了Set集合的約束??梢栽贖ibernate的網(wǎng)站中查看針對(duì)該問題的更多的討論內(nèi)容, 這不是Hibernate的問題, 而是普通的對(duì)象的一致性與相等行的Java語義問題。 推薦使用業(yè)務(wù)鍵值的相等性來實(shí)現(xiàn)equals()和hashCode()方法。業(yè)務(wù)鍵值相等意思是在equals方法中之比較有關(guān)業(yè)務(wù)的屬性值。 這個(gè)關(guān)鍵值可以在現(xiàn)實(shí)世界中唯一標(biāo)示一個(gè)實(shí)例(一個(gè)自然的候選關(guān)鍵字): public class Cat { ... public boolean equals(Object other) { if (this == other) return true; if ( !(other instanceof Cat) ) return false; final Cat cat = (Cat) other; if ( !cat.getLitterId().equals( getLitterId() ) ) return false; if ( !cat.getMother().equals( getMother() ) ) return false; return true; } public int hashCode() { int result; result = getMother().hashCode(); result = 29 * result + getLitterId(); return result; } }一個(gè)業(yè)務(wù)關(guān)鍵字不一定是固定的候選主鍵(參考13.1.3章節(jié))。不變的或者獨(dú)一無二的屬性都是很好的業(yè)務(wù)關(guān)鍵字的候選。 4.4 動(dòng)態(tài)模型 注意: 下面的特性是實(shí)驗(yàn)性的,在將來會(huì)有所改變。在運(yùn)行時(shí)持久化實(shí)體不是必須要被表示為一個(gè)POJO類或者JavaBean對(duì)象。Hibernate也支持動(dòng)態(tài)模型。 使用這種方法,你不需要寫持久化類,只需要映射文件。 默認(rèn)情況下, Hibernate在普通的POJO模式下工作。你可以使用default_entity_mode配置選項(xiàng),為特定的SessionFactory設(shè)置 默認(rèn)的實(shí)體表示模型(參考3.3 “Hibernate 配置屬性”, default_entity_mode選項(xiàng)可以不用配置,session可以自己判斷 )。 下面的示例演示了使用MapS表示模型。首先, 在映射文件中需要聲明entity-name來替換類名, 或者除了類名之外還要聲明entity-name: <hibernate-mapping>
<class entity-name="Customer">
<id name="id"
type="long"
column="ID">
<generator class="sequence"/>
</id>
<property name="name"
column="NAME"
type="string"/>
<property name="address"
column="ADDRESS"
type="string"/>
<many-to-one name="organization"
column="ORGANIZATION_ID"
class="Organization"/>
<bag name="orders"
inverse="true"
lazy="false"
cascade="all">
<key column="CUSTOMER_ID"/>
<one-to-many class="Order"/>
</bag>
</class>
</hibernate-mapping> 雖然是用目標(biāo)類名來聲明冠梁的,但是關(guān)聯(lián)的目標(biāo)類型除了是POJO之外,也可以是一個(gè)動(dòng)態(tài)的實(shí)體。 在你給SessionFactory設(shè)置默認(rèn)的實(shí)體模型為dynamic-map之后, 在運(yùn)行時(shí)你可以使用Maps: Session s = openSession(); Transaction tx = s.beginTransaction(); // Create a customer Map david = new HashMap(); david.put("name", "David"); // Create an organization Map foobar = new HashMap(); foobar.put("name", "Foobar Inc."); // Link both david.put("organization", foobar); // Save both s.save("Customer", david); s.save("Organization", foobar); tx.commit(); s.close(); 動(dòng)態(tài)映射的好處是,變化所需要的時(shí)間少了, 因?yàn)閳A形不需要實(shí)現(xiàn)實(shí)體類, 然而, 你無法進(jìn)行編譯期的類型檢查, 并可能由此會(huì)處理很多的運(yùn)行期異常。 幸虧有了Hibernate映射, 他使得數(shù)據(jù)庫的schema可以容易的規(guī)格化和合理化, 并允許稍后再此之上添加合適的領(lǐng)域模型實(shí)現(xiàn)。 實(shí)體表示模式也能在每個(gè)Session的基礎(chǔ)上設(shè)置: Session dynamicSession = pojoSession.getSession(EntityMode.MAP);//getSession(EntityMode mode)方法沒找到。
// Create a customer
Map david = new HashMap();
david.put("name", "David");
dynamicSession.save("Customer", david);
...
dynamicSession.flush();
dynamicSession.close()
...
// Continue on pojoSession 注意:使用的EntityModel調(diào)用getSession()是在Session的API中,而不是SessionFactory。 這樣新的額Session共享底層的JDBC鏈接, 事務(wù),和其他的上下文信息。這意味著你不需要再第二個(gè)Session中調(diào)用flush()和close(),同樣的, 把事務(wù)和鏈接的處理交給原來的工作單元。 4.5 元組片段映射 |
|