1. 程式人生 > >Nhibernate學習教程(2)-- 第一個NHibernate程序

Nhibernate學習教程(2)-- 第一個NHibernate程序

collect 單元測試框架 文件映射 deb color rtu etc erb session管理

NHibernate之旅(2):第一個NHibernate程序

本節內容

  • 開始使用NHibernate
  • 1.獲取NHibernate
  • 2.建立數據庫表
  • 3.創建C#類庫項目
  • 4.設計Domain
    • 4-1.設計持久化類
    • 4-2.編寫映射文件
  • 5.數據訪問層
    • 5-1.輔助類
    • 5-2.編寫操作
  • 6.數據訪問層的測試
    • 6-1.配置NHibernate
    • 6-2.測試
  • 結語

開始使用NHibernate

我們親自動手,一步一步搭建一個NHibernate程序來,我以一個實際場景電子交易程序來模擬,客戶/訂單/產品的經典組合。由於是第一次使用NHibernate,所以我們的目的是映射一張表並完成使用NHibernate來讀取數據,下面的一幅圖片給了我們第一印象。我們按照基本開發軟件思想的流程一步一步完成。

我使用的開發環境:Microsoft Visual Studio 2008 SP1、SQL Server 2008 Express、NHibernate 2.1.1GA。

技術分享

1.獲取NHibernate

使用官方2009年10月31日最新發布的NHibernate-2.1.1.GA版本。如果你第一次使用NHibernate,先到這裏下載NHibernate最新版本(包括源碼、發布版本、參考文檔、API文檔,可選擇下載)。如果用到NHibernate的擴展項目到這裏下載獲得NHibernate Contrib最新版本。NHibernate-2.1.1.GA是.NET2.0平臺的最後一個版本,關於NHibernate-2.1.1.GA的更多信息請點擊這裏。

關於NHibernate2.1版本的一些說明:

NHibernate2.1版本改變了ByteCode延遲加載機制,有三種3種IoC框架動態代理方式,分別為:Castle框架、LinFu框架、Spring.Net框架。我們只要選擇一種,在配置文件中配置proxyfactory.factory_class節點。

如果使用Castle.DynamicProxy2動態代理,引用NHibernate.ByteCode.Castle.dll程序集並配置proxyfactory.factory_class節點為<property name="proxyfactory.factory_class"> NHibernate.ByteCode.Castle.ProxyFactoryFactory,NHibernate.ByteCode.Castle</property>

如果使用LinFu.DynamicProxy動態代理,引用NHibernate.ByteCode.LinFu.dll程序集並配置proxyfactory.factory_class節點為<property name="proxyfactory.factory_class"> NHibernate.ByteCode.LinFu.ProxyFactoryFactory,NHibernate.ByteCode.LinFu</property>

如果使用Spring.Aop動態代理,引用NHibernate.ByteCode.Spring.dll程序集並配置proxyfactory.factory_class節點為<property name="proxyfactory.factory_class"> NHibernate.ByteCode.Spring.ProxyFactoryFactory,NHibernate.ByteCode.Spring</property>

另外NHibernate2.1要求.NET2.0 SP1以上版本 (System.DateTimeOffset),請使用VS2005的,務必打上Sp1補丁。推薦使用VS2008以上版本。

2.建立數據庫表

由於第一次使用,還是按照我們傳統的從數據庫表配置吧。

打開SQL Server Management Studio Express,新建一個新的數據庫NHibernateSample,創建四個表:分別為客戶表、訂單表、訂單產品表、產品表。

技術分享

3.創建C#類庫項目

由於是我們第一個程序,所以我沒有按照Domain Driver Design方法去設計這個程序,按照大家的常規思想來實現的,以後有機會再介紹Domain Driver Design設計。

註意為什麽創建C#類庫項目呢?在現在軟件設計中,大多數都是采用多層架構來設計,比較經典的三層架構(頁面表示層,業務邏輯層,數據訪問層)通常而言業務邏輯層和數據訪問層都是使用類庫設計,頁面表示層用Web應用程序設計,它引用業務邏輯層和數據訪問層類庫DLL程序集。

使用VS2008創建C#類庫的項目,命名為NHibernateSample。打開項目文件夾,在其項目文件目錄上新建SharedLibs文件夾,把下載NHibernate相關程序集文件拷貝到SharedLibs文件夾下。如下圖,這裏我選擇Castle框架動態代理:

技術分享

創建項目,結構如下:

技術分享

  • Domain(領域模型):用於持久化類和O/R Mapping操作
  • Data(Data Access Layer數據訪問層):定義對象的CRUD操作
  • Data.Test(數據訪問層測試):對數據訪問層的測試,這裏我使用Nunit單元測試框架
  • Web:Web頁面(這篇文章中暫未實現,請參考我的博客其他文章)
項目引用
  • Domain:引用Iesi.Collections.dll程序集(Set集合在這個程序集中)和Castle動態代理
  • Data:引用NHibernate.dll和Iesi.Collections.dll程序集和動態代理相關程序集,Domain引用
  • Data.Test:引用NHibernate.dll和Iesi.Collections.dll程序集,nunit.framework.dll程序集(測試框架),Domain和Data引用

4.設計Domain

4-1.編寫持久化類

按簡單傳統.NET對象(POCOs,Plain Old CLR Objects(Plain Ordinary CLR Objects))模型編程時需要持久化類。在NHibernate中,POCO通過.NET的屬性機制存取數據,就可以把它映射成為數據庫表。

現在為Customer編寫持久化類來映射成為數據庫表。新建一個Customer.cs類文件:

namespace NHibernateSample.Domain.Entities
{
    public class Customer
    {
        public virtual int Id { get; set; }
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
    }
}
規則
  • NHibernate使用屬性的getter和setter來實現持久化。
  • 屬性可設置為public、internal、protected、protected internal或private
註意NHibernate默認使用代理功能,要求持久化類不是sealed的,而且其公共方法、屬性和事件聲明為virtual。在這裏,類中的字段要設置為virtual,否則出現“failed: NHibernate.InvalidProxyTypeException : The following types may not be used as proxies: NHibernateSample.Domain.Entities.Customer: method get_Id should be virtual,method set_Id should be virtual”異常。

4-2.編寫映射文件

小提示我們要為Microsoft Visual Studio 2008添加編寫NHibernate配置文件智能提示的功能。只要在下載的NHibernate裏找到configuration.xsd和nhibernate-mapping.xsd兩個文件並復制到X:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas目錄即可。

NHibernate要知道怎樣去加載和存儲持久化類的對象。這正是NHibernate映射文件發揮作用的地方。映射文件包含了對象/關系映射所需的元數據。元數據包含持久化類的聲明和屬性到數據庫的映射。映射文件告訴NHibernate它應該訪問數據庫裏面的哪個表及使用表裏面的哪些字段。

這裏,我為Customer.cs類編寫映射文件。新建一XML文件,命名為Customer.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
   assembly="NHibernateSample.Domain"
   namespace="NHibernateSample.Domain.Entities">
  
  <class name ="Customer">
    <id name="Id" column ="CustomerId">
      <generator class ="native"/>
    </id>
    <property name ="FirstName"/>
    <property name ="LastName"/>
  </class>
</hibernate-mapping>
註意XML文件的默認生成操作為“內容”,這裏需要修改為“嵌入的資源”生成,因為NHibernate是通過查找程序集中的資源文件映射實體,使用.NET Reflector查看程序集: 技術分享 否則出現“ failed: NHibernate.MappingException : No persister for: NHibernateSample.Domain.Entities.Customer”異常。

5.編寫數據訪問層

5-1.輔助類

我們現在可以開始NHibernate了。首先,我們要從ISessionFactory中獲取一個ISession(NHibernate的工作單元)。ISessionFactory可以創建並打開新的Session。一個Session代表一個單線程的單元操作。 ISessionFactory是線程安全的,很多線程可以同時訪問它。ISession不是線程安全的,它代表與數據庫之間的一次操作。ISession通過ISessionFactory打開,在所有的工作完成後,需要關閉。 ISessionFactory通常是個線程安全的全局對象,只需要被實例化一次。我們可以使用GoF23中的單例(Singleton)模式在程序中創建ISessionFactory。這個實例我編寫了一個輔助類NHibernateHelper 用於創建ISessionFactory並配置ISessionFactory和打開一個新的Session單線程的方法,之後在每個數據操作類可以使用這個輔助類創建ISession 。

public class NHibernateHelper
{
    private ISessionFactory _sessionFactory;
    public NHibernateHelper()
    {
        _sessionFactory = GetSessionFactory();
    }
    private ISessionFactory GetSessionFactory()
    {
        return (new Configuration()).Configure().BuildSessionFactory();
    }
    public ISession GetSession()
    {
        return _sessionFactory.OpenSession();
    }
}

5-2.編寫操作

在Data中新建一類NHibernateSample.cs,編寫一方法GetCustomerId用於讀取客戶信息。在編寫方法之前,我們需要初始化Session。

protected ISession Session { get; set; }
public NHibernateSample(ISession session)
{
    Session = session;
}

NHibernate有不同的方法來從數據庫中取回對象。最靈活的方式是使用NHibernate查詢語言(HQL),是完全基於面向對象的SQL。

public void CreateCustomer(Customer customer)
{
    Session.Save(customer);
    Session.Flush();
}
public Customer GetCustomerById(int customerId)
{
    return Session.Get<Customer>(customerId);
}

6.編寫數據訪問層的測試

6-1.配置NHibernate

我們可以幾種方法來保存NHibernate的配置,具體以後來介紹,這裏我們使用hibernate.cfg.xml文件來配置,不過不必擔心,這個文件我們可以在src\NHibernate.Config.Templates文件夾下找到,直接復制到Data.Test中修改一下配置信息和文件輸出屬性就可以了。

<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
    <session-factory>
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
        <property name="connection.connection_string">
            Data Source=.\SQLEXPRESS;Initial Catalog=NHibernateSample;
      Integrated Security=True;Pooling=False
        </property>
        <property name="adonet.batch_size">10</property>
        <property name="show_sql">true</property>
        <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
        <property name="use_outer_join">true</property>
        <property name="command_timeout">10</property>
        <property name="query.substitutions">true 1, false 0, yes ‘Y‘, no ‘N‘</property>
     <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, 
      NHibernate.ByteCode.Castle</property>
    <mapping assembly="NHibernateSample.Domain"/>    
    </session-factory>
</hibernate-configuration>
註意XML文件的默認“復制到輸出目錄”為“不復制”,這裏需要修改為“始終復制”。否則出現“failed: NHibernate.Cfg.HibernateConfigException : An exception occurred during configuration of persistence layer. ----> System.IO.FileNotFoundException : 未能找到文件“NHibernateSample\NHibernateSample.Data.Test\bin\Debug\hibernate.cfg.xml””異常。

6-2.測試

好了,終於可以使用我們的方法了,這裏新建一個測試類NHibernateSampleFixture.cs來編寫測試用例:調用NHibernateSample類中GetCustomerId方法查詢數據庫中CustomerId為1的客戶,判斷返回客戶的Id是否為1。

[TestFixture]
public class NHibernateSampleFixture
{
    private NHibernateSample _sample;
    [TestFixtureSetUp]
    public void TestFixtureSetup()
    {
        _sample = new NHibernateSample();
    }
    [Test]
    public void GetCustomerByIdTest()
    {
        var tempCutomer = new Customer {FirstName = "李", LastName = "永京"};
        _sample.CreateCustomer(tempCutomer);
        Customer customer = _sample.GetCustomerById(1);
        int customerId = customer.Id;
        Assert.AreEqual(1,customerId);
    }
}

我們使用TestDriven.NET測試一下這個方法:OK,測試通過。這裏我使用NHibernate監視器NHibernate Profiler查看結果:

技術分享

技術分享

結語

在這篇文章中,我們使用NHibernate來構建了一個最基本的項目,沒有體現NHibernate更多細節,只描繪了NHibernate的基本面目。當然使用NHibernate有各種各樣的程序架構,我按照一般模式構建的。請大家在實際項目中不要參考關於Session管理部分,本系列未做處理,更多實戰知識以後介紹。

Nhibernate學習教程(2)-- 第一個NHibernate程序