標籤:test ros cto 安全 ati 補丁 init 添加 equal
NHibernate之旅(2):第一個NHibernate程式
本節內容
- 開始使用NHibernate
- 1.擷取NHibernate
- 2.建立資料庫表
- 3.建立C#類庫項目
- 4.設計Domain
- 5.資料訪問層
- 6.資料訪問層的測試
- 結語
開始使用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.設計Domain4-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程式