Nhibernate+SQLite 入门实例指南二 类的继承、多态关系
?昨天忘記向源代碼下載了,現(xiàn)在補上第一章的代碼:http://files.cnblogs.com/9527/QuickStart1.rar
實例二、類的繼承、多態(tài)關(guān)系
在我們實際設計過程中,經(jīng)常碰到類的繼承關(guān)系,比如一個電子產(chǎn)品商店,同時銷售手機和MP3,所以在設計系統(tǒng)的時候我們把手機和MP3的共性如品牌、名稱等抽象為一個類,而把它們的特性比如MP3有內(nèi)存容量,手機有號碼等,我們以不同的子類來體現(xiàn)。如下圖:
在實際數(shù)據(jù)庫的時候,最簡單的就是每個子類擁有一個獨立的表分別對應Mp3player和MobilePhone
由于MobilePhone和Mp3Player都是繼承electronic,所以他們都Id,Name,Brand等屬性,了我們分別為兩個表編寫映射文件:
MobilePhone.hbm.xml
<?xml?version="1.0"?encoding="utf-8"??>?<hibernate-mapping?xmlns="urn:nhibernate-mapping-2.0">?
<class?name="QuickStart2.Data.MobilePhone,?QuickStart2.Data"?table="t_mobilephone"?>?
<id?name="Id"?column="id"?type="Int32">?
<generator?class="identity"?/>?
</id>?
<property?name="Name"?type="String(100)"?column="name"?/>?
<property?name="Brand"?type="String(20)"?column="brand"?/>?
<property?name="Phonenumber"?type="String(13)"?column="phonenumber"?/>?
</class>?
</hibernate-mapping>?
Mp3Player.hbm.xml?
<?xml?version="1.0"?encoding="utf-8"??>?
<hibernate-mapping?xmlns="urn:nhibernate-mapping-2.0">?
<class?name="QuickStart2.Data.Mp3Player,?QuickStart2.Data"?table="t_mp3player"?>?
<id?name="Id"?column="id"?type="Int32">?
<generator?class="identity"?/>?
</id>?
<property?name="Name"?type="String(100)"?column="name"?/>?
<property?name="Brand"?type="String(20)"?column="brand"?/>?
<property?name="Mensize"?type="Int32"?column="mensize"?/>?
</class>?
</hibernate-mapping>?
可以看到這兩個映射和普通的映射文件沒有什么不同。我們編寫了一個段測試代碼:
?
ISession?session=null;?ArrayList?list=null;?
try{?
session=SessionFactory.OpenSession();?
list=(ArrayList)session.CreateCriteria(typeof(electronic)).List();?
}?
catch(Exception?e)?{?
System.Console.WriteLine(e.Message);?
System.Console.ReadLine();?
}?
finally{?
session.Close();?
}?
foreach(electronic?el?in?list)?{?
System.Console.WriteLine("名稱:o"+el.Name);?
}?
運行結(jié)果如下圖所示:
我們看到NHibernate更據(jù)electronic自動找到它的兩個子類Mp3Player和MobilePhone,生存兩鐵絲SQL語句分別查詢兩個表,下面輸出的是,查詢出來的結(jié)果。
為什么會這樣子,在NHibernate中是用多態(tài)(polymorphism)來進行描述兩個繼承于同一父類的子類情況,在映射文件的Class節(jié)點中也有一個polymorphism的屬性用來設定是隱式還是顯式的使用查詢多態(tài),為什么我們的映射類中沒有出現(xiàn)這個屬性的設定呢,polymorphism?=?implicit是默認的。所以我們?nèi)绻M行的是隱式的查詢就可以不用進行設定。以下是摘自博客園renrenqq?翻譯的NHibernate中文文檔中對polymorphism的解釋:
Implicit (隱式)的多態(tài)是指,如果查詢中給出的是任何超類、該類實現(xiàn)的接口或者該類的名字,都會返回這個類的實例;如果查詢中給出的是子類的名字,則會返回子類的實例。Explicit?(顯式)的多態(tài)是指,只有在查詢中給出的明確是該類的名字時才會返回這個類的實例;同時只有當在這個?<class>?的定義中作為?<subclass>?或者?<joined-subclass>?出現(xiàn)的子類,才會可能返回。?大多數(shù)情況下,默認的polymorphism="implicit"都是合適的。?顯式的多態(tài)在有兩個不同的類映射到同一個表的時候很有用。(允許一個“輕型”的類,只包含部分表字段)。
通過這樣的方式我們雖然也實現(xiàn)了我們想要的結(jié)果,但是對經(jīng)驗豐富的設計人員來說,這樣的設計是并不合理的,一旦父類分生了變動,數(shù)據(jù)庫里兩個表都必須修改,而且從性能角度上來說也并不怎么理想。
所以,更據(jù)經(jīng)驗我們一般會吧兩個表相同的字段合并成一個表,另建兩個新表,只包含Mp3Player和MobilePhone的特有的屬性。經(jīng)過修改我們的數(shù)據(jù)庫結(jié)構(gòu)如下圖如示:
可以看到主表于子表之間通過外鍵向連。
數(shù)據(jù)庫修改以后,我們要重新設計映射文件,讓它正確的映射到關(guān)系型數(shù)據(jù)庫。
Electronic.hbm.xml
?
<?xml?version="1.0"?encoding="utf-8"??>?<hibernate-mapping?xmlns="urn:nhibernate-mapping-2.0">?
<class?name="QuickStart2.Data.electronic,?QuickStart2.Data"?table="t_electronic">?
<id?name="Id"?column="id"?type="Int32">?
<generator?class="identity"?/>?
</id>?
<property?name="Name"?type="String(100)"?column="name"?/>?
<property?name="Brand"?type="String(20)"?column="brand"?/>?
<joined-subclass?name="QuickStart2.Data.MobilePhone,QuickStart2.Data"?table="t_mobile">?
<key?column="id"?/>?
<property?name="Phonenumber"?type="String(13)"?column="phonenumber"?/>?
</joined-subclass>?
<joined-subclass?name="QuickStart2.Data.Mp3Player,QuickStart2.Data"?table="t_mp3">?
<key?column="id"?/>?
<property?name="Mensize"?type="Int32"?column="mensize"?/>?
</joined-subclass>?
</class>?
</hibernate-mapping>?
通過映射文件我們可以看到,我們?yōu)橹黝惤⒘擞成?#xff0c;兩個子類在<joined-subclass>節(jié)點下進行了配置。
我們現(xiàn)編寫一段數(shù)據(jù)插入代碼來看看,NHibernate是怎么進行數(shù)據(jù)插入的
?
public?static?void?SaveMobilephone()?{?
ISession?session=null;?
ITransaction?t=null;?
try?
{?
session=SessionFactory.OpenSession();?
t=session.BeginTransaction();?
MobilePhone?mp=new?MobilePhone();?
mp.Name="575";?
mp.Brand="Dopod";?
mp.Phonenumber="13151921698";?
Mp3Player?mp3=new?Mp3Player();?
mp3.Name="SB200";?
mp3.Brand="小霸王";?
mp3.Mensize=513;?
session.Save(mp3);?
session.Save(mp);?
session.Flush();?
t.Commit();?
}?
catch(HibernateException?e)?
{?
System.Console.Write(e.Message.ToString());?
if(t!=null)?
{?
try?
{?
t.Rollback();?
}?
catch(HibernateException?e1)?
{?
System.Console.Write(e1.Message.ToString());?
}?
}?
}?
finally?
{?
session.Close();?
}?
System.Console.ReadLine();?
}?
編譯運行如上代碼,在返回中我們看到如下結(jié)果
根據(jù)圖片,我們可以看到,和前一次不同,NHibernate分四次,分別對主表和子表進行插入。
在運行我們在上一節(jié)中的查詢代碼,其結(jié)果是
我們可以看到,NHibernate用了一條組合查詢,一次性就把三個表所有數(shù)據(jù)查詢了出來。
從上面的例子我們可以看到,這樣的設計,雖然從設計的邏輯上來說更加清晰明了,符合我們的設計習慣,但是多表操作帶來的性能的消耗來是相當?shù)目捎^,因此,如果我們的系統(tǒng)對性能上有相當?shù)囊?#xff0c;我們就要考慮第三種方式。
我們把數(shù)據(jù)設計成不僅包含用父類的共同屬性,也同是用不同的字段來表示兩種產(chǎn)品的不同特性,這樣如何來區(qū)別兩個類呢,我們在數(shù)據(jù)庫中加入一個”category”的字段來區(qū)別兩種產(chǎn)品。
代碼方面我們需要修改的也只有數(shù)據(jù)庫的映射文件,把新映射文件修改成如下:
?
<?xml?version="1.0"?encoding="utf-8"??>?<hibernate-mapping?xmlns="urn:nhibernate-mapping-2.0">?
<class?name="QuickStart2.Data.electronic,?QuickStart2.Data"?table="t_elec">?
<id?name="Id"?column="id"?type="Int32">?
<generator?class="identity"?/>?
</id>?
<discriminator?column="category"?type="String(10)"?/>?
<property?name="Name"?type="String(100)"?column="name"?/>?
<property?name="Brand"?type="String(20)"?column="brand"?/>?
<subclass?name="QuickStart2.Data.MobilePhone,QuickStart2.Data"?discriminator-value="1"?>?
<property?name="Phonenumber"?type="String(13)"?column="phonenumber"?/>?
</subclass>?
<subclass?name="QuickStart2.Data.Mp3Player,QuickStart2.Data"?discriminator-value="2"?>?
<property?name="Mensize"?type="Int32"?column="mensize"?/>?
</subclass>?
</class>?
</hibernate-mapping>?
于前一節(jié)中的映射文件不一樣的是,我們在映射文件中加入了一個識別器(discriminator),用來指定數(shù)據(jù)庫中哪個字段是用來做為標識的。
在定義的子類的時候,也不能用joined-subclass 而要改成subclass joined-subclass不能支持discriminator-value屬性,discriminator-value就是用來區(qū)分獨立的子類當我們完成數(shù)據(jù)庫的插入操作后(具體代碼可以用上一節(jié)所提供的代碼,由于代碼完全相同,所以不再次提供了)我們可以看到,NHibernate只用了兩次插入動作就完成了對數(shù)據(jù)的插入。
我們再運行查詢的代碼也可以用一條簡單的SQL語句來完成操作,大家也可以試著用
list=(ArrayList)session.CreateQuery("from Mp3player").List();
或
list=(ArrayList)session.CreateQuery("from MobilePhone").List();
進行查詢,在NHibernate生的結(jié)果如下圖:
可以看到,NHibernate在讀取數(shù)據(jù)的時候會自動更據(jù)標識讀取Mp3Player或MobilePhone的內(nèi)容。
但是這種方法也有它的硬傷,如果子類的特性太多,哪數(shù)據(jù)庫的可讀性就大打折扣了,甚至可以讓人抓狂,對于系統(tǒng)的后期維護升級非常的不利。
因此、三種方法各有各的優(yōu)點也各有缺點,我們要在設計的過程中更據(jù)實際情況進于權(quán)衡,然后才確定采用何種方式。
第二章代碼下載:http://files.cnblogs.com/9527/QuickStart2.rar
? ? 本文轉(zhuǎn)自無心之柳.NET博客園博客,原文鏈接:http://www.cnblogs.com/9527/archive/2006/09/24/513505.html,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的Nhibernate+SQLite 入门实例指南二 类的继承、多态关系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谷歌 Pixel 6 魔法橡皮擦功能下放
- 下一篇: LOL手游薇恩出装天赋技能