什么是NHibernate
NHibernate 是一個基於.net 的針對關系型數據庫的對象持久化類庫。NHibernate 來源於非常優秀的基於Java的Hibernate 關系型持久化工具。
NHibernate 從數據庫底層來持久化你的.net 對象到關系型數據庫。NHibernate 為你處理這些,遠勝於你不得不寫SQL去從數據庫存取對象
。你的代碼僅僅和對象關聯,NHibernat 自動產生SQL語句,並確保對象提交到正確的表和字段中去。
這篇文檔意在讓你盡可能快的開始使用NHibernate。它將介紹如何持久化一個簡單的對象到一張表里,完成對表的操作。
開發的過程
我們將進行以下步驟:
1.新建一個將要持久化.net對象的表
2.構建一個需要被持久化的.net類
3.構建一個可以讓NHibernate知道如何持久化對象屬性的映射文件
4.構建一個讓NHibernate知道如何連接數據庫的配置文件
5.使用NHibernate的API
6.測試
第一步:寫構建表的SQL
這里我們將使用的是一個非常簡單的例子。假設你正在為你的網站開發一個基本的用戶管理子系統。我們將使用如下的一張User表(假定你已經設置好一個數據庫—例子里我稱它為test)。
CREATE TABLE users (
LogonID integer not null ,
Name nvarchar(40) default NULL,
Password nvarchar(20) default NULL,
EmailAddress nvarchar(40) default NULL,
LastLogon datetime default NULL,
PRIMARY KEY (LogonID)
)
我使用的是sqlite, 但也可以使用任何數據庫,只要你有關於它們的基於.net數據提供驅動程序。我們將得到一個含有LogonID,Name, Password, Email 和LastLogon的表. 經過以上標准步驟,我們下一步是寫一個.net類處理一個給定的User對象。
第二步:產生一個.Net 類文件
當內存中有一堆User對象的時候,我們需要某種對象去保存它們。NHibernate通過對象屬性的反射來工作,因此我們需要添加我們希望持久化的對象屬性。一個可以被NHibernate持久化的類應該看起來象下面的樣子:
using System; namespace NHibernate.Domain { public class User { public virtual int Id { get; set; } public virtual string UserName { get; set; } public virtual string Password { get; set; } public virtual string EmailAddress { get; set; } public virtual DateTime LastLogon { get; set; } } }
第三步:寫映射文件
現在我們有數據表和需要去映射它的.net類。我們需要一種方式去讓NHibernate知道如何從一個映射到另一個。這個任務依賴於映射文件來完成。最易於管理的辦法是為每一個類寫一個映射文件,如果你命名它是YourObject.hbm.xml 並且把它放在和類的同一個目錄里,NHiberante將會使得事情簡單起來。下面是一個User.hbm.xml的例子:
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Domain" namespace="NHibernate.Domain"> <class name="NHibernate.Domain.User,NHibernate.Domain" table="users" > <id name="Id" column="LogonId" type="int" unsaved-value="0"> <generator class="increment"/> </id> <property name="UserName" column= "Name" type="String" length="40"/> <property name="Password" type="String" length="20"/> <property name="EmailAddress" type="String" length="40"/> <property name="LastLogon" type="DateTime"/> </class> </hibernate-mapping>
讓我們來看看這個文件中讓我們感興趣的某些行。第一個有趣的標簽是class。這里我們將映射類型名稱到我們數據庫中的User表,這里和Hibernate有一點點的不同。你將不得不告訴NHibernate從何處提取對象。
讓我們先跳過id標簽,來討論property標簽。簡要看一下,你將發現NHibernate所要做的工作。name屬性的值正是我們.net 類的屬性,column屬性值將是我們數據庫里的字段。type屬性是可選的(如果你不標明,NHibernate將利用反射進行最佳的推測)。
好了,讓我們回到標簽id,你可以猜測到這個標簽將是映射數據庫表的主鍵,的確如此,id標簽的組成和我們剛才看的property標簽是相似的。我們映射屬性到目標數據庫的字段。
內嵌的generator標簽告訴NHibernate 如何生成主鍵(它將恰當的為你生成主鍵,不管你指定何種類型,但你必須告訴它)。
提示:請將user.hbm.xml的Build Action屬性設置為Embedded Resource。
第四步:為你的數據庫產生一個配置文件
我們至今還沒有告訴NHibernate 去哪里連接數據庫。最直接的辦法是在你的應用程序的配置文件里設置一個NHibernate配置節。這和在Hibernate里使用屬性文件是等價的。如下配置(hibernate.cfg.xml):
<?xml version="1.0" encoding="utf-8" ?> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" > <session-factory name="NHibernate.Test"> <property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property> <property name="connection.connection_string"> Data Source=..\output\test.db </property> <property name="dialect">NHibernate.Dialect.SQLiteDialect</property> <property name="show_sql">true</property> <mapping assembly="NHibernate.Domain" /> </session-factory> </hibernate-configuration>
上面的例子里用了sqlite驅動,在本地連接名稱為test的數據庫,記得引用System.Data.SQLite.dll,否則運行時會報錯。這里還有其他屬性你需要調整來確定如何讓NHibernate來訪問數據庫。再次說明,你可以在文檔里獲取更多信息。
請注意以上的配置里並沒有涉及到log4net的配置信息。NHibernate使用log4net來記錄內部發生的一切。在一個應用程序產品里,在你特定環境里,我推薦配置log4net,並為NHibernate設置一定的日志級別。
第五步:開始展現NHibernate的魔力
所有艱苦的工作已經完成。你將有以下內容
User.cs ----你需要持久化的C#類
User.hbm.xml ----你的NHibernate映射文件
hibernate.cfg.xml ----對數據庫連接的配置信息(如果你願意,你可以在代碼中實現)。
你的數據庫里有一張User表。
現在可以在你的代碼中恰當簡潔的使用NHibernate。
為了讓你更清晰,我們來看一些代碼。
首先創建一個數據庫連接類(NHibernateHelper.cs):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using NHibernate.Cfg; namespace NHibernate.DataPortal { class NHibernateHelper { private ISessionFactory sessionFactory; public NHibernateHelper() { sessionFactory = GetSessionFactory(); } private ISessionFactory GetSessionFactory() { return (new Configuration()).Configure().BuildSessionFactory(); } public ISession GetSession() { return sessionFactory.OpenSession(); } } }
NHibernate在建樹數據庫連接之前,須要讀取配置文件,然后創建會話(ISession)。在會話中完成各類對數據庫的操縱。
然后建立一個數據庫操作類(UserDal.cs):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using NHibernate.Domain; namespace NHibernate.DataPortal { public class UserDal { private NHibernateHelper nhibernateHelper = new NHibernateHelper(); protected ISession Session { get; set; } public UserDal() { this.Session = nhibernateHelper.GetSession(); } public UserDal(ISession session) { this.Session = session; } public void AddUser(User user) { var aa = Session.Save(user); Session.Flush(); } public void DeleteUser(User user) { Session.Delete(user); Session.Flush(); } public void UpdateUser(User user) { Session.Update(user); Session.Flush(); } public IList<User> GetUsers() { return Session.QueryOver<User>().List(); } } }
第六步:效果測試
新建一個wpf app界面:
數據庫交互:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using NHibernate.DataPortal; using NHibernate.Domain; namespace TestApp { /// <summary> /// MainWindow.xaml 的交互邏輯 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private UserDal ud = new UserDal(); private void button1_Click(object sender, RoutedEventArgs e) { //Add(); //Delete(); //Update(); Select(); } private void Add() { User user = new User() { UserName = "Jame", Password = "123456", EmailAddress = "abc@163.com", LastLogon = DateTime.Now }; ud.AddUser(user); } private void Delete() { User user = new User() { Id = 3 }; ud.DeleteUser(user); } private void Update() { User user = new User() { Id = 1, UserName = "Jame1", Password = "1234561", EmailAddress = "abc1@163.com", LastLogon = DateTime.Now }; ud.UpdateUser(user); } private void Select() { IList<User> list = ud.GetUsers(); listView1.ItemsSource = list; } } }
測試結果:
親!真心不錯吧!