NHibernate搭建教程

1. 第一個NHibernate應用程序

1.1. 開始NHibernate之旅

這個教程演示瞭如何在微軟開發環境裏搭建一個NHibernate 2.0.0例子. 使用了以下工具:

  1. Internet 信息服務(IIS)管理器 - ASP.NET支持的Web服務器.

  2. SQL Server 2005 - 數據庫服務器. 這個例子裏面使用的是桌面版本(EXPRESS), 可以從微軟免費下載. NHibernate也支持其他數據庫,更換數據庫要做的僅僅是在配置文件裏更改數據庫方言和數據庫驅動。

  3. Visual Studio .NET 2005 - 開發環境.

首先,我們創建一個Web項目.項目命名爲QuickStart。 項目會自動的創建一個http://localhost/QuickStart虛擬目錄。 打開項目,添加NHibernate.dll引用。Visual Studio會自動的將你引用的庫的這個庫的依賴文件拷貝到你的輸出目錄. 如果你使用其他數據庫,請添加對應的數據訪問程序集到你的項目。

我們現在開始爲NHibernate配置數據庫連接信息。在這之前,打開項目裏面自動生成的Web.config文件按照下面的方式添加一個配置元素: 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <!-- Add this element -->
    <configSections>
        <section
            name="hibernate-configuration"
            type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"
        />
    </configSections>

    <!-- Add this element -->
    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
        <session-factory>
            <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
            <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
            <property name="connection.connection_string">
                Server=(local);initial catalog=quickstart;Integrated Security=SSPI
            </property>
            <mapping assembly="QuickStart" />
        </session-factory>
    </hibernate-configuration>

    <!-- Leave the system.web section unchanged -->
    <system.web>
        ...
    </system.web>
</configuration>

<configSections>在配置文件裏定義了一個配置節並且聲明瞭這個配置節裏面的數據如何解析。

<hibernate-configuration> 配置包含了NHibernate的配置信息,告訴NHibernate我們使用 Microsoft SQL Server 2005數據庫並且通過指定的連接字符串連接數據庫. 方言(dialect)是必選設置,每個數據庫對SQL標準的解釋都不一樣。 NHibernate通過方言(dialect)來消除這些這些開源或者是商業數據庫之間對SQL標準的解釋的差異。

ISessionFactory在NHibernate裏面是一個單個數據存儲的概念(在SQLServer裏面就是對應一個database),多數據庫操作可以使用創建多個XML配置文件以及在程序裏創建多個Configuration ISessionFactory對象來實現。

<mapping assembly="QuickStart" />該節點聲明瞭 QuickStart作爲包含持久化類以及對應映射文件所在的應用程序集名稱。
注意:如果忽略此節點,NHibernate將無法自動載入數據映射文件

 映射文件包含POCO類映射到一個或者多個數據庫表的元數據信息。我們待會就會提到映射文件。首先我們來寫一個POCO類,然後爲這個類寫一個數據庫映射文件。

1.2. 第一個持久化類

NHibernate使用簡單的.Net對象(Plain Old CLR Objects ,就是POCOs,有時候也稱作Plain Ordinary CLR Objects)這種編程模型來進行持久化,POCO類通過set和get屬性 訪問其內部成員變量,對外則隱藏了內部實現的細節(假若需要的話,NHibernate也可以直接訪問其內部成員變量)。 

namespace QuickStart
{
    public class Cat
    {
        private string id;
        private string name;
        private char   sex;
        private float  weight;

        public Cat()
        {
        }

        public virtual string Id
        {
            get { return id; }
            set { id = value; }
        }

        public virtual string Name
        {
            get { return name; }
            set { name = value; }
        }

        public virtual char Sex
        {
            get { return sex; }
            set { sex = value; }
        }

        public virtual float Weight
        {
            get { return weight; }
            set { weight = value; }
        }
    }
}



NHibernate對屬性使用的類型不加任何限制。所有的.NET類型和原始類型(比如string,charDateTime)都可以被映射,也包括.Net 集合(System.Collections)中的類。你可以把它們映射成爲值,值集合,或者與其他實體類相關聯。Id是一個特殊的屬性,代表了這個類的數據庫標識符(主鍵),對於類似於Cat這樣的實體類我們強烈建議使用。NHibernate也可以使用內部標識符,但這樣我們會失去一些程序架構方面的靈活性。

持久化類不需要實現什麼特別的接口,也不需要從一個特別的持久化根類繼承下來。NHibernate也不需要使用任何編譯期處理,比如IL操作,它獨立的使用.Net反射機制和運行時類增強(通過Castle.DynamicProxy2 library)。所以不依賴於NHibernate(POJO的類不需要依賴NHibernate),我們就可以把POJO的類映射成爲數據庫表。

爲了讓上面提到運行時類增強功能生效,NHibernate持久化類的所有的public的屬性必須聲明爲virtual。


1.3. 映射cat

Cat.hbm.xml映射文件包含了對象/關係映射(O/R Mapping)所需的元數據。元數據包含持久化類的聲明和屬性到數據庫的映射(指向字段和其他實體的外鍵關聯)。

注意:Cat.hbm.xml在Visual Stuido裏面要設置爲嵌入式資源(embedded resource)。 

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="QuickStart" assembly="QuickStart">

    <class name="Cat" table="Cat">

        <!-- A 32 hex character is our surrogate key. It's automatically
            generated by NHibernate with the UUID pattern. -->
        <id name="Id">
            <column name="CatId" sql-type="char(32)" not-null="true"/>
            <generator class="uuid.hex" />
        </id>

        <!-- A cat has to have a name, but it shouldn' be too long. -->
        <property name="Name">
            <column name="Name" length="16" not-null="true" />
        </property>
        <property name="Sex" />
        <property name="Weight" />
    </class>

</hibernate-mapping>

每個持久化類都應該有一個標識屬性(實際上,這個類只代表實體,而不是獨立的值類型類, 後者會被映射稱爲實體對象中的一個組件)。這個屬性用來區分持久化對象:如果catA.Id.Equals(catB.Id)結果是true的話, 這兩個Cat就是相同的。這個概念稱爲數據庫標識。NHibernate附帶了幾種不同的標識符生成器, 用於不同的場合(包括數據庫本地的順序(sequence)生成器、hi/lo高低位標識模式、和程序自己定義的標識符)。 我們在這裏使用UUID生成器(只在測試時建議使用,如果使用數據庫自己生成的整數類型的鍵值更好), 並指定Cat表中的CatId字段(作爲表的主鍵)存放生成的標識值。

All other properties of Cat are mapped to the same table. In the case of theName property, we mapped it with an explicit database column declaration. This is especially useful when the database schema is automatically generated (as SQL DDL statements) from the mapping declaration with NHibernate'sSchemaExport tool. All other properties are mapped using NHibernate's default settings, which is what you need most of the time. The tableCat in the database looks like this: Cat的其他屬性都映射到同一個表的字段。對Name屬性來說, 我們把它顯式地聲明映射到一個數據庫字段。如果數據庫schema是通過由映射聲明自動生成的(作爲SQL DDL指令)的話, 這就特別有用。所有其它的屬性都用NHibernate的默認值映射,大多數情況你都會這樣做。數據庫中的Cat表看起來是這樣的:

 
 Column |     Type     | Modifiers
--------+--------------+----------------------
 CatId  | char(32)     | not null, primary key
 Name   | nvarchar(16) | not null
 Sex    | nchar(1)     |
 Weight | real         |


1.4. 與Cat同樂

我們現在可以開始使用NHibernate的ISession了。它是一個 持久化管理器, 我們通過ISession來從數據庫中存取Cat。首先,我們要從ISessionFactory中獲取一個ISession(NHibernate的工作單元)。

ISessionFactory sessionFactory =
            new Configuration().Configure().BuildSessionFactory();

ISessionFactory代表一個數據庫,並且使用一個XML配置文件(Web.config或者hibernate.cfg.xml)。 NHibernate通過對Configuration().Configure()的調用來裝載配置文件,並初始化成一個Configuration實例。通過Configuration實例創建一個ISessionFactory。 在創建 ISessionFactory之前(它是不可變的),你可以訪問Configuration來設置其他屬性(甚至修改映射的元數據)。 我們應該在哪兒創建ISessionFactory,在我們的程序中又如何訪問它呢?

ISessionFactory通常只是被初始化一次,比如說在Application_Start事件裏來初始化。 這意味着你不應該在ASP.NET頁面中把它作爲一個實例變量來持有,而應該放在其他地方。進一步的說, 我們需要使用單例(Singleton)模式,我們才能更容易的在程序中訪問ISessionFactory。 下面的方法就同時解決了兩個問題:對ISessionFactory的初始配置與便捷使用。

下面實現了一個名爲NHibernateHelper的幫助類:

using System;
using System.Web;
using NHibernate;
using NHibernate.Cfg;

namespace QuickStart
{
    public sealed class NHibernateHelper
    {
        private const string CurrentSessionKey = "nhibernate.current_session";
        private static readonly ISessionFactory sessionFactory;

        static NHibernateHelper()
        {
            sessionFactory = new Configuration().Configure().BuildSessionFactory();
        }

        public static ISession GetCurrentSession()
        {
            HttpContext context = HttpContext.Current;
            ISession currentSession = context.Items[CurrentSessionKey] as ISession;

            if (currentSession == null)
            {
                currentSession = sessionFactory.OpenSession();
                context.Items[CurrentSessionKey] = currentSession;
            }

            return currentSession;
        }

        public static void CloseSession()
        {
            HttpContext context = HttpContext.Current;
            ISession currentSession = context.Items[CurrentSessionKey] as ISession;

            if (currentSession == null)
            {
                // No current session
                return;
            }

            currentSession.Close();
            context.Items.Remove(CurrentSessionKey);
        }

        public static void CloseSessionFactory()
        {
            if (sessionFactory != null)
            {
                sessionFactory.Close();
            }
        }
    }
}

這個類不用考慮ISessionFactory,應爲它被設置爲static類型的,並且將ISessionhttp請求之中。

ISessionFactory是安全線程,可以由很多線程併發訪問並獲取到ISessions。 單個ISession不是安全線程對象,它只代表與數據庫之間的一次操作。ISession通過ISessionFactory獲得並在所有的工作完成後關閉。

ISession session = NHibernateHelper.GetCurrentSession();

ITransaction tx = session.BeginTransaction();

Cat princess = new Cat();
princess.Name = "Princess";
princess.Sex = 'F';
princess.Weight = 7.4f;

session.Save(princess);
tx.Commit();

NHibernateHelper.CloseSession();

在一個ISession中,每個數據庫操作都是在一個事務(transaction)中進行的, 這樣就可以隔離開不同的操作(甚至包括只讀操作)。 我們使用NHibernate的ITransaction API來從底層的事務策略中(本例中是ADO.NET事務)脫身出來。 注意這個例子沒有包含任何異常處理。

注意:你可以隨心所欲的多次調用NHibernateHelper.GetCurrentSession();,你每次都會得到同一個當前請求的Session。 不管是在你的Application_EndRequest代碼中,或者在Application_EndRequest中還是在HTTP結果返回之前, 你都必須確保這個Session在你的數據庫訪問工作完成後關閉。這樣做還有一個好處就是可以容易的使用延遲裝載(lazy initialization):ISession在渲染view層的時候仍然打開着的,所以你在遍歷當前對象圖的時候可以裝載所需的對象。

NHibernate有不同的方法用來從數據庫中取回對象。最靈活的方式就是使用NHibernate查詢語言(HQL),這是一種容易學習的語言,是對SQL的面向對象的強大擴展

using(ITransaction tx = session.BeginTransaction())
    {
    IQuery query = session.CreateQuery("select c from Cat as c where c.Sex = :sex");
    query.SetCharacter("sex", 'F');
    foreach (Cat cat in query.Enumerable())
        {
        Console.Out.WriteLine("Female Cat: " + cat.Name);
        }
    tx.Commit();
    }

Hibernate也提供一種面向對象的按條件查詢API,可以執行簡潔安全類型的查詢。 當然,NHibernate在所有與數據庫的交互中都使用IDbCommand和參數綁定。你也可以使用NHibernate的直接SQL查詢特性, 或者在特殊情況下從ISession獲取一個原始的ADO.NET連接。 

1.5. 總結

在這個短小的教程中,我們對NHibernate的淺嘗即止。請注意我們沒有在例子中包含任何ASP.NET相關代碼。 你必須自行編寫ASP.NET Page,並插入合適你的NHibernate代碼。

請記住NHibernate作爲一個數據庫訪問層,是與你的程序緊密相關的。 通常情況下,所有其他層次都依賴持久機制。請確信你理解了這種設計的內涵  


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