Step 1 Nhibernate 學會簡單使用

對於DataSet的編碼直接破壞了透明性。他很明顯知道在你代碼裏面是用的存儲機制,他直接影響你編碼的方式。另一種存儲途徑是使用ORM工具。Microsoft正在開發這樣一個框架(ObjectSpaces),但是最近宣佈他將推遲到2006年。NHibernate,一種OpenSource的解決方案,已經存在並且可以用來解決同樣的一系列問題。使用NHibernate,你的代碼和你的數據庫結構可以(),在OR層唯一可見的實物就是映射文件。通過NHibernate,你將看到:這個OR框架是由一系列配置文件組成(連接到數據庫,標識數據方言)以及將你的領域對象映射到數據表。


現在有很多的ORM框架,包含一些商業的和一些開源的。本文的目的是關注NHibernate這個ORM。他有很多的來自Java世界的驅動,以及他非常容易上手。但是,如果你對本文講的大體的技術有興趣,我建議看一下其他更合適呢需求的存在選擇。


第一,你要從http://www.nhibernate.sourceforge.net/下載這個框架。在你的程序集裏面引用它。下一步在你的程序配置裏面增加NHibernate配置,告訴他你要存儲的東西。本文使用MSSQL,雖然你可以很簡單的轉換到Oracle,MySQL或者其他的數據庫。爲了映射SQL Server實例,你的配置如下:

xml version="1.0" encoding="utf-8" ?>

<configuration>


<configSections>

<section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />

configSections>


<nhibernate>

<add key="hibernate.show_sql" value="true" />

<add key="hibernate.connection.provider"

value="NHibernate.Connection.DriverConnectionProvider" />

<add key="hibernate.dialect"

value="NHibernate.Dialect.MsSql2000Dialect" />

<add key="hibernate.connection.driver_class"

value="NHibernate.Driver.SqlClientDriver" />

<add key="hibernate.connection.connection_string"

value="data source=(local);database=MySchool;user id=sa;password=1980;connection reset=false;connection lifetime=5; min pool size=1; max pool size=50" />

nhibernate>

configuration>

 

一旦你配置好這個框架來識別你數據的存儲,下一步就是建立你的領域模型和數據庫表現。沒有一個固定的順序,如果你的程序建立在數據庫結構已經建立好的基礎上,從這開始是合適的。否則,如果數據庫就是一個存儲對象的地方,那麼從領域模型開始可能更有意義。還有第三種選擇,從映射文件開始,映射文件描述了類與數據庫表之間的關係。現在NHibernate提供了一個工具它可以從映射文件中自動生成DDL。這個項目最近增加了對NAnt任務的支持,他將通過映射文件自動生成C#代碼文件。綜上所述,你可以通過就建立映射文件這個實現基礎,來使用NHibernate工具作剩下的事情。


領域模型

我們將從領域模型開始。在這篇文章裏面,我們關注一個企業級程序裏面的一小部分。明確的說,我們將從大學的註冊系統開始。爲了這個目的,我們設計下面幾個類:

1. Department:描述大學的系

2. UniversityClass:學校的一個班級

3. Professor:學校的教授

4. Student:學生

每一個類有他自己的數據字段,但是他們之間的關係如下:


Department可以有 0,1,或者更多的Professor。一個Professor可以教很多個Department。一個Department包含了大於等於1個Class。一個Class只屬於一個Department。一個Class只能被一個Professor交,但是一個Professor可以教幾個Class。一個Class包含很多學生。在Department與Student之間沒有什麼直接的關係。


我們的領域對象非常簡單。下面是類與數據字段:


當然,你可以提供Public屬性來包裝這些字段,那是一種好的編程習慣。雖然NHibernate可以通過Private,Protected字段來工作,通過屬性來訪問字段更加有意義。


第二,記住Professor和Student共享一個表。在領域模型裏面,他們共享幾個數據字段。在我們的領域模型裏面,通過繼承來表現這個關係。在這個方案裏面,他們實現一個Person接口來表現。


最後,你將看到我們的集合字段是使用IDictionary來定義的。當你在你的領域裏面定義你的集合,緊貼這個系統提供的接口。這通常是一個好的實踐,他給予NHibernate最大的寬鬆。

數據庫:


現在讓我們看一下數據庫。第一個表是Department,只是簡單的存儲ID和名字。下一步,我們將爲Student與Professor建立表。但是,如果你仔細看,Professor與Student幾乎是差不多的(顯而易見,他們都屬於人類)。他們有First與Last name,和一些字符串標誌(Professor的Title,學生的SNN)。替代著2個表,我們建立一個表叫Person。他對於每一個人將有一個唯一的ID,他們的Fisrt Last Name,一個標誌字段,一個叫PersonType的字段(我們用來區別Student與Professor),最後,我們需要一個班級表。他有一個唯一的ID,關於班級所有的描述信息,&2個外鍵,PersonID(與教這個班級的Professor關聯),DeptID(這個班級屬於哪一個Department)。

 

其他2個表是聯合標,用於構建Student與Class,Department與Professor之間的many-to-many的關係。這2個表簡單的匹配合適的原表ID,形成一個聯合。


映射文件


下一步是提供映射文件用來從數據表來填充我們的領域對象。每一個類多需要自己的映射文件,可以存儲你喜歡的東西。我們保持我的方式(與類文件結合以至於簡單的操作當我改變模型的時候)。不管怎樣,在你的程序裏面每一個持久類作一個映射。


映射文件關聯你的類與數據庫裏面的持久屬性。你的類可以有非之久化屬性。這是關於透明數據庫層的一種很好的方式。如果你的領域對象調用運行時計算屬性,你的類可以與持久化對象混合。你的映射文件可以忽略非持久化屬性。


讓我們開始爲Department建立映射。所有的映射文件是XML文件。他們開始於xml version="1.0" encoding="utf-8" ?>

下一步生命這個文件是NHibernate的映射文件。NHibernate的根部元素象這樣:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">

hibernate-mapping>
 

這是樣板文件,現在讓我們開始建立真實的映射內容。第一我們需要告訴NHibernate哪一個類被映射(使用標籤)。當我們要給NHibernate類型時,我們需要給全名。對於Department來書全名就是“TestNH.DomainObjects. Department”,程序集是“TestNH”。我們需要爲類填充表明。在這個方案裏面department

<class name="TestNH.DomainObjects.Department,TestNH" table="department">

class>
 

我們做的很好。剩下的就是將持久化字段映射到數據庫結構。所有的屬性映射共享一個共同的特徵:類上面屬性,數據庫表結構裏面的列,以及要持久還字段類型。不管怎樣的屬性,上面三項多會出現。


讓我們看一下標準屬性:Department的Name屬性。這個屬性聲明爲string,數據庫裏面定義NVarchar(50).這個屬性非常直接。

<property name="Name" column="deptname" type="string(50)">property>
 

所有類的標準屬性跟這個差不多。注意:跟在類型後面的長度不在需要,現在NHibernate不贊成,將反射處理配置。事實上,最新的版本,你可以同type屬性一起刪除。NHibernate將會檢查映射屬性的類型。


一個比較有趣的是Department的ID字段。每一個類有一個字段包含數據唯一標識。對於♂的模型,每一個類多有ID屬性(爲了這種目的)。你必須提供標準的屬性集,以及2個注意的地方(generator,unsaved-value)。


ID字段的Generator是讓NHbernate知道,唯一標誌符怎麼建立:由程序員,由NHibernate,或者數據庫本身。不同的程序有不同的主鍵生成方式,不同的數據庫爲管理這些值提供了不同唯一的服務,以至於你必須基於你的需求與你的構架小心的挑選。Generator有下面這些值:

l Identity:數據庫標誌類型,MSSQL2000,MySQL 等等

l Sequence:唯一值(DB2,Oracle)

l Hilo:使用Hi/lo算法來生成標誌符的值

l Native:自由選擇


我們將使用native。Unsaved-value屬性是爲Id屬性指定一個默認值當這個對象還沒有持久化的時候。在這個方案裏面,既然♂讓ID屬性的創建由數據庫管理,使用默認值是非常有用的。

<id name="ID" column="ID" type="Int32" unsaved-value="null">

<generator class="native">generator>

id>
 

到現在我們看看配置文件

xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">

<class name="TestNH.DomainObjects.Department,TestNH" table="department">

<id name="ID" column="ID" type="Int32" unsaved-value="null">

<generator class="native">generator>

id>

<property name="Name" column="deptname" type="string(50)">property>

class>

hibernate-mapping>
 


如果我們就這樣,我們通過映射文件從數據庫裏面裝載東西,♂可以得到Department列表(包含ID,Name值),但是Classes與Professors將是null。,因爲♂沒有在映射文件裏面映射。如果一個屬性不被映射,他將被NHibernate忽略。


下面,我們來處理Collection屬性(他們得特殊的需求)。讓我們看一看類。一個UniversityClass實例列表。記住我們這個模型的需求:一個department包含多個UniversityClass,但是一個UniversityClass只屬於一個department。這是one-to-many的關係。對於這個模型,♂使用(或者)來映射一個集合,不是一個單一實例。

<bag name="Classes">

<key column="DeptID">key>

<one-to-many class="TestNH.DomainObjects.UniversityClass,TestNH"/>

bag>
 

Bag對應的IList,而Set對應的是Set


NHibernate 進階

作者:Justin Gehtland


(原文:請點擊這裏)
    在我的最近文章中,我介紹了 Nhibernate。在這裏和在其他的論壇中 , 因爲我沒有強調NHibernate 只是許多可得的 ORM 解決方案之一,(事實上,現在對.NET開發者來說,開源的加上商業的 ORM 的架構現在是超過 50個可供選擇)。 作爲一個開發顧問,我會經常用到Hibernate(大家都知道它吧)既然我必須在.NET平臺下選擇一個,NHibernate是我最明智的選擇。 我想在這裏脫離.NET平臺來研究一下這個框架,並談談我們能從它獲得的益處。

我的上一篇文章中介始示範了應用Nhibernate建一個簡單應用(大學註冊登記)的起步示例。下面我將介紹更多使用Nhibernate的技術,這次我們的目標給你一些在對特別大數據量查詢的高吞吐量、高併發性的應用需求下使用Nhibernate的方式。

爲了達到這個目標,我將分成下面四部分來講:最佳的Session管理方式,指導使用HQL查詢數據庫,怎樣延遲載入對象集合及對象生存週期管理。

 

第一部分:會話管理

在我的前一篇文章中,我實現了一個非常簡單的爲管理SessionFactory和Sessionr的名爲RegMgr的類:它在其構造函數中根據配置創建了一個SessionFactory,然後在每一個方法中使用SessionFactory創建Session,使用這種方式有幾個問題。

首先, 每個RegMgr 對象都需要建造一個新的 SessionFactory, 這將耗費非常昂貴資源。 每個SessionFactory都意味對你的應用中的實體與相應的數據庫進行一次建模。其實僅僅在你應用需要多個數據庫的支持才需創建多個SessionFactory的實例,而我的簡單例子不是,所以無需這樣。

    第二,每個方法從這個Factory創建了一個新的Session。這種方式每當方法完成都會關閉Session並釋放鎖定的數據庫,從而提供了最大程度的併發保護機制。然後這也結束這個會話所有關聯對象的狀態,其實Session創建也比較耗費資源的,雖然不像SessionFactory那樣。

第一個問題的答案是可以肯定的,那就是確認你只創建 SessionFactory 一次。 RegMgr 原來是這樣的:

public class RegMgr : DBMgr
{
        Configuration config;
        ISessionFactory factory;
              
        public RegMgr()
        {
               try
               {
                       config = new Configuration();
                       config.AddClass(typeof(nhRegistration.Department));
                       config.AddClass(typeof(nhRegistration.Person));
                       config.AddClass(typeof(
                               nhRegistration.UniversityClass));
                       factory = config.BuildSessionFactory();
               }
               catch (Exception ex)
               {
                       // handle exception
               }
        }
        // etc...
}
應修改如下:

public class RegMgr : DBMgr
{
        static Configuration config;
        static ISessionFactory factory;
 
        static RegMgr()
        {
               try
               {
                       config = new Configuration();
                       config.AddClass(typeof(nhRegistration.Department));
                       config.AddClass(typeof(nhRegistration.Person));
                       config.AddClass(typeof(
                               nhRegistration.UniversityClass));
                       factory = config.BuildSessionFactory();
               }
               catch (Exception ex)
               {
                       // handle exception
               }
        }
        // etc...
}
這樣,所有RegMgr的實例所共享了這同一個SessionFactory,這就節省大量資源。

    

     看起來用同樣的方式來解決Session管理的問題也會一樣好,那爲什麼不將一個Static的Session加入到這個類中並僅僅在那個SessionFactory中創建並打開它呢,然後所有的方法都使用同一個Session。答案有兩個:首先,共享的Static的Session被多個線程同時訪問時可能是線程不安全的,各個事物(Transiction)會相互干擾的;其次,它也大部分時處在空閒狀態,但是還是保持一物理數據庫連接。而數據庫連接是非常珍貴的資源。每一種數據訪問方式都有一個相同的目標就是使服務端的遊標與一個客戶端的連接維持在最短的時間內,Nhibernate也同樣如此。因此,無所事事開着的Session相反會是一個很費資源的方式。

     替代的解決方案是使用一個非連接態的Session對象:爲你所有調用的函數創建一個共享的Session實例或靜態對象,在其每個函數的調用開始打開它,離開函數總是關閉它。代碼可能是這樣的:

public IList getClasses()
{
        IList classes = null;
        try
        {
               // session is declared in instance scope
               session.Reconnect();
               ITransaction tx = session.BeginTransaction();
               classes = session.CreateCriteria(
                       typeof(UniversityClass)).List();
              
        }
        catch (Exception ex)
        {
               // handle exception
        }
        finally
        {
               session.Flush();
               session.Disconnect();
}
        return classes;
}
    這樣你總能重用同一個Session對象,這樣不同方法因調用Session所花費的資源會減到最少,而數據庫的資源也都會因及時釋放也會使它們協同工作得很好。

 

第二部分:HQL

我們有時需要NHibernate來處理如:“查詢所有部門”或“查詢某個學生”之類更特殊更復雜的需求。具體應用中可能需要提供複雜的搜索與數據過濾操作來執行數據查詢。NHibernate 提供了與SQL很相似的HQL(the Hibernate Query Language) 。 在 HQL 和 SQL 之間的最大不同點在FROM子句:在HQL中可以使用一個或多個類來表示SQL中的一個或多個表名。既然 NHibernate 的目標就是用Domain objects來提供一個透時的數據層,既然Domain objects與數據表具有對應關係,那麼就不再需要提供表名給Nhibernate了。

舉例來說,在我的“University registration”程序中,我們可能想知道那些班已安排好但還沒有分配任課教師。知道哪一班級已經被預定但是尚未被分配Professors會更好。( 順便我們可能需要知道其中那些是一年級的班級)。我們爲得到它們可以在RegMgr中添加這樣一個方法:

public IList getClassesNoProf(){}
然後使用NHibernate來進行完整的實現:

IList classes = this.getClasses();
IList results = new ArrayList();
foreach(UniversityClass c in classes)
{
        if(c.Prof == null) results.Add(c);
}
return results;
     這裏我從數據庫獲取所有的班級然後遍歷它們,並獲得最終符合條件的班級。 這樣可能會很慢,因爲獲取了所有對象而最後能需要其中一些甚至很少的一部分,數據表越大這種方式會越慢而難以接受。

     所以我們要做的是數據庫中直接過濾,這可使數據在我們程序之間的網絡帶寬需求降至最低(因爲數據庫通常在網絡中的其它服務器上)。

public IList getClassesNoProf()
{
        IList results = null;
        try
        {
               ISession session = factory.OpenSession();
               results = session.Find(
                       "from nhRegistration.UniversityClass as
                       uc where personid is null");
        }
        catch (Exception ex)
        {
               // handle exception
        }
        return results;
實現一個 HQL 查詢主要是通過調用 ISession.Find() 方法。 使用它可以執行任意一個查詢。 HQL 支持幾乎所有SQL子句, 如排序和分組(order by,group by)。爲了得到相同的而按Name屬性排序的UniversityClass對象集合只需對這個查詢做這樣的改變就以了:

results = session.Find("from nhRegistration.UniversityClass as
uc where personid is null order by uc.Name asc");
特別注意: 審查排序子句的語法。這裏我們按Name來排序,如果你參考我上一篇文章中的映射文件中就有一個名爲 “classname”的列。當書寫Order子句時,既可以使用屬性名也可以數據表的列名,但是如果選擇屬性你就不得不使用類的別名作爲前綴(這個例中就是uc),而使用列名時則不需要(“order by classname asc”)。我寧願使用類別名加上屬性我的方式,因爲使我的代碼與數據庫相分離。

這個HQL查詢缺少普通SQL中的SELECT子句,這實際暗示地告訴NHibernate 返回所有From中出現的類型的所有實例。 有時我們並不需要整個對象,比如我們可能僅需要顯示課程的名稱而無需知道其教師是誰,這時如果載入並初始化這些實例就有些過了,爲了克服這個缺點,就可以加入SELECT子句來表示你需要的屬性,這樣你將得到一個僅包含那些屬性的Ilist。在我們的示例中是這樣的:

public IList getClassNamesNoProf()
{
        IList results = null;
        try
        {
               ISession session = factory.OpenSession();
               results = session.Find("select uc.Name from
                       nhRegistration.UniversityClass as uc
                       where personid is null order by uc.Name asc");
        }
        catch (Exception ex)
        {
               string s = ex.Message;
        }
        return results;
}
同時,我們也能僅僅得到沒有老師的班級數量。

results = session.Find("select count(uc.Name) from
nhRegistration.UniversityClass as uc where personid is null");
     正如你所看到的, HQL在大部分地方與SQL相似,除了用面象對象描述來替換數據元素。對於大多數正常的對象持久化工作你完全可以不理會HQL,但是爲使更多以數據爲中心的工作能完成得更快,善於HQL就會事半功倍。

         第三部分:延遲載入(Lazy Loading)

     NHibernate一個最棒的地方就是完透明地載入父類的相應子類。你僅僅要求得到父類的時候,而 NHibernate 會去載入所有的子類無論是這種一對一還是一對多的關係。如果這是唯一的選項,那這也是Nhibernate最壞的事情。

    這種缺省行爲的問題是你的代碼對於數據庫的使用完全透明而在代碼運行時一點也不透明。我的意思因爲所有關係被裝載對於任何大小的樹對象模型來說可能是非常慢的。

    現在就以“University registration”的 Domain model爲例:這裏僅有四個類,但當載入單個Department對象時,就會同時載入一個UniversityClass的集合、Processor的集合。而每一個UniversityClass也會載入一個Processor對象和包括很多Student對象的集合。如果數據庫的裏有足夠多的數據, 僅僅載入一個Department對象已是很笨重了。現在想象一個RegMgr.getAllDepartments()方法,問題就很明顯了。

     解決這個問題的方法是延遲集合對象的載入。要聲明一個要延遲載入一個對象集合很簡單,只需要在映射文件中相應元素添加一個特性:lazy=”true” 。 舉例來說, 要使我們Deparment延遲載入集合,原來的映射文件是這樣的:

<set name="Classes" cascade="all">
        <key column="deptid"/>
        <one-to-many class="nhRegistration.UniversityClass,
               nhRegistration"/>
</set>
現在只需做如下修改就可以了:

<set name="Classes" cascade="all" lazy="true">
        <key column="deptid"/>
        <one-to-many class="nhRegistration.UniversityClass,
               nhRegistration"/>
</set>
延遲載入的意思就是直到需要載入集合中的元素纔將它們載入。這樣你延遲了加載了時間,同時如果當你的執行代碼從來不使用它們的時候這些集合對象根本就不會被載入。比如執行的代碼可能需要訪問一個具有一個或多個Processor的Department,而對於那些不符合條件的Department,就可能從不需要載入它的UniversityClass集合, 這就節省了許多時間( 無論是客戶端應用還是數據庫)。

     但是這有一個缺點就是延遲載入需要最初裝載父對象的Session來載入。要是你的代碼象我的大學註冊應用一樣,即將所有的數據管理都放進了一個單一的數據管理類,這樣你才能在在這人數據管理類中看到延遲載入好處。讓我們再看一下RegMgr.getDepartments():

public IList getDepartments()
               {
        IList depts = null;
        try
        {
               ISession session = factory.OpenSession();
               ITransaction tx = session.BeginTransaction();
               depts = session.CreateCriteria(typeof(Department)).List();
                       session.Close();
        }
        catch (Exception ex)
        {
               // handle exceptions
        }
        return depts;
}
 

對有力的技術缺點是,被延期的負荷需要最初的會議裝載父母物體用來裝載懶惰的收集。 如果你的密碼跟隨我們已經爲大學登記申請用的式樣,即分開所有的數據管理進一個單一數據經理班級,然後你才能在那一個數據經理班級中見到懶惰載入的利益。再一次看 RegMgr.getDepartments():

    這裏我們載入所有部門後產刻關閉了Session。當類的相關集合標記爲延遲載入時,如果你嘗試在業務代碼中訪問相關集合,這裏你會獲得一個“LazyInitializationException”的異常:這就意味着你既不能訪問集合中的某個成員也不能獲取集合中相關的合計數據如成員總數,因爲它根本不存在。並且因爲Session已經關閉,它將再也不會將工作,除非你將這個集合對象的父對象關聯到另外一個Session。

    所以,你可以選擇將任何需要有益於延遲載入業務邏輯代碼移入到數據管理類中,或者選擇直到從這個方法返回之前都不關閉Session。我建議,除非你對這個實現費了很長時間或者有足夠多的異常處理代碼,否則你不要選擇後者。

 

第四部分:攔截機制與持久對象生存週期(Interceptors and Persistent Lifecycle)

    持久化對象在其生存週期中有四個主要時刻:即被裝載,更新,保存和刪除四個時刻( 記住, 保存是指一個新對象第一次被持久化,而更新發生在提交改時的對象時。), 更新發生當你委託對一個現有的物體變化)。 在我們已有代碼中, 你能在這些時候做些事情的唯一方法是在數據管理類中相應方法中來加點你需要的代碼(如getDepartment() 或 saveStudent())。但問題是,它們僅僅在數據管理類中,而如果它們是持久化對象總是需要的一部分, 這樣做你就可能就將持久化對象與你的數據管理類大過緊密地聯繫在一起了。

如果持久化對象可以自己處理這些事刻這樣會清晰。NHibernate 提供一個接口使Nhibernate在相應生存週期的時刻通知類的實例。這個接口是 ILifecycle,它是這樣被定義的:

      public NHibernate.LifecycleVeto OnUpdate(ISession s){}
      public void OnLoad(ISession s, object id){}
      public NHibernate.LifecycleVeto OnSave(ISession s){}
      public NHibernate.LifecycleVeto OnDelete(ISession s){}
四個方法中有三個都會返返回一個LifecycleVeto,來決定對象下一步的生命週期事件處理。這樣你就可以在保存對象之前,檢查對象狀態來決定更新或刪作它,並且如果這些狀態不符要求的條件,也可以取消對象的保存。如果取消了也就意味對象的其它操作也會失敗,也就是對象不會被保存、更新或刪除。

四個方法中的三個給你的物體一個機會藉由歸還 LifecycleVeto 更進一步停止給定的生命週期事件的處理。使用這一個機制,你能在~之前解救質問物體的內在狀態,更新或劃除它,而且如果那州不符合你的申請一些標準,你能否決事件的完成。 歸還否決權導致事件的其它部分默默地失敗, 這意謂,物體沒有在解救, 更新或劃除,但是沒有那一種事實的通知是申請的可得其他地方。 相反將在這些引用它們的方法中產生一個異常。

這三個方法最初是爲了提供程序員自己來處理相互依賴對象之間相關係來替代Nhibernate處理的一種可選方式。 (你能更大範圍對層級關聯對象進行控制)但是你不應該使用Onload方法去做它,雖然你能夠象NHibernate缺省行爲一樣。

    攔截是類實現了IInterceptor 接口。這些類實現了相同類型的生存週期方法 (其它一些生存週期方法) ,但是這些在類中被定義的方法會在Session中任一一個對象的生存週期事件發生時被調用。並且在這個攔截接口中你也不能否決事件繼續運行,但是你能修改對象並返回一個表明是否你做過修改的布爾值。加上在Iinterceptor中發生的事件是很多的:

public int[] FindDirty(object entity, object id,
        object[] currentState, object[] previousState, string[]      propertyNames, NHibernate.Type.IType[] types){}
public object Instantiate(Type type, object id){}
public bool OnFlushDirty(object entity, object id, object[]
        currentState, object[] previousState, string[] propertyNames,
        NHibernate.Type.IType[] types){}
public object IsUnsaved(object entity){}
public bool OnLoad(object entity, object id, object[] state, string[]
        propertyNames, NHibernate.Type.IType[] types){}
public bool OnSave(object entity, object id, object[] state, string[]
        propertyNames, NHibernate.Type.IType[] types){}
public void OnDelete(object entity, object id, object[] state, string[]
        propertyNames, NHibernate.Type.IType[] types){}
public void PreFlush(System.Collections.ICollection entities){}
public void PostFlush(System.Collections.ICollection entities){}
    在“University Registration”這個示例中,我想要實現一個一致的統一的日誌機制。爲了做那,我創建了一個LoggingInterceptor 的類, 它將在任何對象載入與持久化時寫一個消息至日誌(其他的沒用方法則不記錄)。

public bool OnLoad(object entity, object id, object[] state, string[]
propertyNames, NHibernate.Type.IType[] types)
{      
        string msg = string.Format("Instance of {0}, ID: {1} loaded.",
entity.GetType().Name, id);
        log(msg);
        return false;
}
 
public bool OnSave(object entity, object id, object[] state, string[]
propertyNames, NHibernate.Type.IType[] types)
{
        string msg = string.Format("Instance of {0}, ID: {1} saved.",
entity.GetType().Name, id);
        log(msg);
        return false;
}
 
private void log(string msg)
{
        // app-specific logging behavior
}
最後就要要在創建Session的時候載入一個這個Interceptor的實例以便能攔截所有對對象的相關操作。

ISession session = factory.OpenSession(new LoggingInterceptor());
這樣所有的被這個Session載入的domain object的載入與保存操作都會被攔截記錄下來日誌。

 

結語:

正如你所見到的,Nhibernate有比一些映射文件和一個叫Session.Find()的更多東西,它有非常大的可擴展性。 對於小而簡單的應用來說,你能使用Nhibernate來處理複雜和很多的數據訪問代碼,不必更多考慮我在這裏談到的各種特徵。如果應用需求越來越大,越來越複雜,這裏談到將很會有用,因爲你知道Nhibernate 幾乎可以定製任何你想怎樣進行對象持久化的特定方式。我們已經差不多對它有了一個大致的瞭解。

 
發佈了7 篇原創文章 · 獲贊 2 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章