前言:
談到NHibernate大伙並不陌生,搞Java的更是清楚,Hibernate是一個目前應用的最廣泛的開放源代碼的對象關系映射框架,它對Java的JDBC(類似於ADO.Net)進行了非常輕量級的對象封裝。NHibernate 是一個基於.Net 的針對關系型數據庫的對象持久化類庫。Nhibernate 來源於非常優秀的基於Java的Hibernate 關系型持久化工具(ORM)。
體系結構
SessionFactory(NHibernate.IsessionFactory):它是Session的工廠,是ConnectionProvider的客戶。可以持有一個可選的(第二級)數據緩存,可以在進程級別或集群級別保存的可以在事物中重用的數據。
會話(NHibernate.ISession):單線程,生命期較短的對象,代表應用程序和持久化層之間的一次對話。封裝了一個ADO.NET連接,也是Transaction的工廠。保存有必需的(第一級)持久化對象的緩存,用於遍歷對象圖,或者通過標識符查找對象。
持久化對象(Persistent)其集合(Collections):生命期較短的單線程的對象,包含了持久化狀態和商業功能。這些可能是普通的對象,唯一特別的是現在從屬於且僅從屬於一個Session。一旦Session被關閉,它們都將從Session中取消聯系,可以在任何程序層自由使用(比如,直接作為傳送到表現層的DTO,數據傳輸對象)。
事務Transaction (NHibernate.ITransaction):(可選)單線程,生命期較短的對象,應用程序用其來表示一批工作的原子操作,它是底層的ADO.NET事務的抽象。一個Session在某些情況下可能跨越多個Transaction事務。
持久化類
持久化類是暫時存在的,實例會被持久性保存於數據庫中.如:virtual public string Name { get; set; }
NHibernate默認使用代理功能,要求持久化類不是sealed的,而且其公共方法、屬性和事件聲明為virtual。
屬性不一定需要聲明為public的。NHibernate可以對default、protected、internal或private的屬性執行持久化.
映射(Mapping)
對象和關系數據庫之間的映射是用一個XML文檔(XML document)來定義的。
使用方法(結合MVC3開發)
- 添加Nugget包:如下圖:
2、在項目中配置NHibernate:
(1)、打開本項目文件夾下有個"packages"文件夾-->NHibernate.3.3.3.4000-->ConfigurationTemplates-->MSSQL.cfg.xml。
(2)、復制MSSQL.cfg.xml到項目根目錄下,改名為”hibernate.cfg.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””異常。
如下圖:
3、數據庫中添加表:Users。
4、在項目中建立”Entities“文件夾,添加Users類。

public class Users { virtual public int ID { get; set; } [DisplayName("姓名")] virtual public string Name { get; set; } [DisplayName("密碼")] virtual public string PassWord { get; set; } [DisplayName("身高")] virtual public string Height { get; set; } [DisplayName("工作")] virtual public string Descript { get; set; [DisplayName("創建時間")] virtual public DateTime CreateTime { get; set; } }
5、添加”Users.hbm.xml“,右鍵屬性:不復制,嵌入的資源。
6、XML出現智能提示,在代碼中右鍵屬性:架構添加:nhibernate-configuration.xsd和nhibernate-mapping.xsd,文件位置如下圖:
7、Users.hbm.xml文檔代碼如下:
(1) <hibernate-mappingxmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateDemo" namespace="NHibernateDemo.Entities">
解釋:定義了NHibernate的版本信息,assembly:加載的程序集名稱。namespace:映射到體類的文件夾。
(2) <class name="Users" table="Users" lazy="false">,name定義了所要映射的類,table定義了要映射的數據庫中的表,lazy定義了是否要延遲加載,如 果是默認值的話lazy=”true”,是延遲加載,這樣的話需要在定義的類字段中加入Virtual,而lazy=”true”則不用延遲加載,立即執行。
(3)<id name="ID" column="ID"><generator class="native"/></id>
這段代碼的作用是被映射的類必須定義對應數據庫的表主鍵字段,屬於int自增的。name標識實體屬性的名字,column標識數據庫主鍵的名字。
(4)<property name="Name"/>字段名稱,如果實體類中的名稱和數據庫中的一致,不需要定義column。

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateDemo" namespace="NHibernateDemo.Entities"> <class name="Users" table="Users" > <id name="ID" column="ID"> <generator class="native"/> </id> <property name="Name"/> <property name="PassWord" /> <property name="Height"/> <property name="Descript"/> <property name="CreateTime"/> </class> </hibernate-mapping>
8、hibernate.cfg.xml文檔代碼如下:
(1) hibernate.dialect 數據庫方言類,NHibernate根據不同的方言來適應不同的數據庫,到0.7版只提供了支持MsSql2000的方言。
(2) hibernate.connection.driver_class 數據庫連接的驅動類
(3) hibernate.connection.connection_string 數據庫的連接字符串,包括主機名,數據庫名,用戶名和密碼,注意,很多實際項目中出於安全性,會將該連接字符串寫入注冊表中,那么該參數就只能在程序中動態賦值了。
(4)將 current_session_context_class 配置為 web,NHibernate 在初始化時會生成 NHibernate.Context.WebSessionContext 類的實例

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" > <session-factory name="NHibernate.Test"> <property name="current_session_context_class">web</property> <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property> <property name="connection.connection_string"> Server=.;initial catalog=TXUsers;User ID=sa;Password=sasa;Integrated Security=SSPI </property> <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property> <mapping assembly="NHibernateDemo"/> </session-factory> </hibernate-configuration>
創建NHibernateHelp類:
(1)、我們要從ISessionFactory中獲取一個ISession(NHibernate的工作單元)。
(2)、ISessionFactory可以創建並打開新的Session。
(3)、一個Session代表一個單線程的單元操作。 ISessionFactory是線程安全的,很多線程可以同時訪問它。
(4)、ISession不是線程安全的,它代表與數據庫之間的一次操作。ISession通過ISessionFactory打開,在所有的工作完成后,需要關閉。
(5)、ISessionFactory通常是個線程安全的全局對象,只需要被實例化一次。我們可以使用單例(Singleton)模式在程序中創建ISessionFactory。
(6)、有了返回的ISession類型的GetSession()方法,就可以實現增刪改查的功能了。
(7)、看了一篇 Session-Per-Request 模式,歸納總結如下:(也同時感謝指出問題的朋友們)
(8)、WebSessionContext 實現了 Session-Per-Request 模式,它封裝了 HttpContext ,因此我們不需要在我們的輔助類(NHibernateSessionFactory 或是 NHibernateHelper)中再對 HttpContext 進行操作。
(9)、我們只需要從 WebSessionContext 的實例中獲取 Session 即可。從WebSessionContext 類中獲取當前 ISession 相當簡單,因為 WebSessionContext 實現了 ICurrentSessionContext 接口。
(10)、在實際使用中我們並不需要直接調用 WebSessionContext 的 CurrentSession() 方法,因為 ISessionFactory 提供了一個更簡單的方法讓我們能一步獲取到 Session。

public sealed class NHibernateHelper { public static readonly ISessionFactory SessionFactory; static NHibernateHelper() { var cfg = new Configuration() .Configure(); SessionFactory = cfg.BuildSessionFactory(); } public static ISession GetCurrentSession() { return SessionFactory.GetCurrentSession(); } public static ISession OpenSession() { return SessionFactory.OpenSession(); } }

public class NHibernateRepository<TEntity, TKey> : Repositories.IRepository<TEntity,TKey> where TEntity: class //where TID: struct { protected ISession GetCurrentSession() { return NHibernateHelper.GetCurrentSession(); } public TEntity GetByID(TKey id) { ISession session = GetCurrentSession(); return session.Get<TEntity>(id); } public IQueryable<TEntity> GetAll() { ISession session = GetCurrentSession(); return session.Linq<TEntity>(); } public TKey Save(TEntity entity) { ISession session = GetCurrentSession(); return (TKey)session.Save(entity); } public void Update(TEntity entity) { ISession session = GetCurrentSession(); session.Update(entity); } public void Delete(TEntity entity) { ISession session = GetCurrentSession(); session.Delete(entity); } }

public class UsersRepository: NHibernateRepository<Users, int> { }

interface IRepository<TEntity, TKey> where TEntity : class { IQueryable<TEntity> GetAll(); TEntity GetByID(TKey id); TKey Save(TEntity entity); void Update(TEntity entity); void Delete(TEntity entity); }
(11)、在全局Global.asax中
注意:// 並不是每一次請求都需要一個 Session 來訪問數據庫。
// 雖然 NHibernate 的 Session 是輕量級的,較為合理的做法是在“真正需要”時綁定。

public MvcApplication() { // 並不是每一次請求都需要一個 Session 來訪問數據庫。 // 雖然 NHibernate 的 Session 是輕量級的,較為合理的做法是在“真正需要”時綁定。 BeginRequest += new EventHandler(MvcApplication_BeginRequest); EndRequest += new EventHandler(MvcApplication_EndRequest); } private void MvcApplication_BeginRequest(object sender, EventArgs e) { ISession session = NHibernateHelper.OpenSession(); CurrentSessionContext.Bind(session); } private void MvcApplication_EndRequest(object sender, EventArgs e) { if (CurrentSessionContext.HasBind(NHibernateHelper.SessionFactory)) { ISession session = WebSessionContext.Unbind(NHibernateHelper.SessionFactory); //session.Flush(); session.Close(); } }
NHibernate的查詢:
分為以下幾種:(我在項目中用的第三種方式(Linq))
-
HQL: NHibernate配備了一種非常強大的查詢語言,這種語言看上去很像SQL。但是不要被語法結構 上的相似所迷惑, HQL是非常有意識的被設計為完全面向對象的查詢,它可以理解如繼承、多態 和關聯之類的概念。

return _session.CreateQuery("from Customer c where c.Firstname=:fn") .SetString("fn", firstname) .List<Customer>();
2、條件查詢(Criteria Query):在NHibernate中,提供了一種直觀的、可擴展的Criteria API。在我們鍵入查詢語句的時候,提供了編譯時的語法檢查,VS提供了強大的智能提示。如果你對HQL的語法感覺不是很舒服的話,用這種方法可能更容易。這種API也比HQL更可擴展。

public IList<Customer> Order() { return _session.CreateCriteria(typeof(Customer)) .Add(Restrictions.Like("Firstname","T%")) .AddOrder(new NHibernate.Criterion.Order("Firstname", false)) .AddOrder(new NHibernate.Criterion.Order("Lastname", true)) .List<Customer>(); }
3、Linq支持:首先得引入 using NHibernate.Linq;和之前你用的Linq是一模一樣的。在NHibernate 3.0.0版本中,Query方式新增了Linq支持和強類型查詢API(QueryOver)兩種查詢方式。

public List<Entities.Users> List() { var List = Session.Query<Users>().ToList(); return List; }
根據前面的總結,很容易的可以在項目中使用NHibernate了,代碼如下:

private UsersRepository repository = new UsersRepository(); // // GET: /Employee/ public ActionResult Index() { IEnumerable<Users> _Users= repository.GetAll(); return View(Users); }

[HttpPost] public ActionResult Create(Users _users) { try { repository.Save(_users); return RedirectToAction("Index"); } catch { return View(_users); } }

[HttpPost] public ActionResult Edit(Users _users) { try { repository.Save(_users); return RedirectToAction("Index"); } catch { return View(_users); } }
總結:
NHibernate不止這么簡單,還有以下內容(本人研究的也不是很深,大家可以加入QQ群:331273083,進行MVC、EF、NHibernate的交流與學習,互相進步嘛):
1、SchemaExport的工具(根據實體類生成數據庫)。
2、NHibernate中使用存儲過程。
3、NHibernate一級緩存、NHibernate二級緩存。
源碼下載:修正版源碼(或者QQ群:331273083 共享里下載!(關於博主的其他示例代碼,也都在共享里。)