[C#/NHibernate] 10分鐘快速體驗NHibernate
最近聽聞專案存取資料庫技術使用的是NHibernate,趕緊趁開工前Study了一下
前言
NHibernate是一套用物件操作方式存取資料庫的Framework
本文以Console專案(.Net4.5)搭配SQL Server Express 2012 做展示
實作
先自行建立一個Console專案後
Step 1 .接著加入相關的.dll一切才能開始
建議剛開始從官網下載壓縮包
本文下載的是NHibernate-3.3.1.GA-bin.zip
下載解壓後把資料夾裡Required_Bins目錄裡的Iesi.Collections.dll和NHibernate.dll加入參考
Q:為什麼不從NuGet套件安裝NHibernate呢?
A:可以是可以,但NuGet只會安裝基本用到的.dll(Iesi.Collections.dll和NHibernate.dll)
玩下去沒多久很快就會卡關,因為一開始就不知道.xml設定檔從何設定起,從官網下載的壓縮包裡面至少還有上手說明,資源較完整
然後還要再加入Lazy Loading會用到的.dll
NHibernate.LinFu
或
NHibernate.Castle
本文使用的是NHibernate.LinFu
從專案右鍵>管理NuGet套件>搜尋NHibernate.LinFu安裝
確認「參考」底下確實有「LinFu.DynamicProxy」、「NHibernate.ByteCode.LinFu」這兩個.dll
沒加入Lazy-Loading會用的.dll的話,到時候程式一執行可能發生
類型 'NHibernate.Bytecode.UnableToLoadProxyFactoryFactoryException' 的未處理例外狀況發生於 NHibernate.dll
或
An exception occurred in the persistence layer.
Step 2.加入NHibernate xml設定檔
從專案右鍵
名稱最好取名:hibernate.cfg.xml
為了要讓此xml檔可以有NHibernate相關的intellisense,從剛剛下載來的壓縮包內加入結構描述
整個設定字串也無須自己慢慢敲打
打開 NHibernate-3.3.1.GA-bin\HowInstall.txt檔
http://nhforge.org/blogs/nhibernate/archive/2008/11/09/nh2-1-0-bytecode-providers.aspx
由於本文使用的是NHibernate.LinFu
貼回hibernate.cfg.xml改一改
並確認複製到輸出目錄為「永遠複製」
Step 3. 為專案加入兩個資料夾:Domain、Mapping
Step 4.加入Entity類別定義
先建好DB Table:Persons (因為我習慣DB First)
(
PersonID int Not NULL identity primary key,
PersonName nvarchar(10) Not NULL default('')
)
Go
新增類別,注意要加上virtual關鍵字
否則可能發生
The following types may not be used as proxies:
NHibernateTest.Domain.Persons: method get_PersonID should be 'public/protected virtual' or 'protected internal virtual'
NHibernateTest.Domain.Persons: method set_PersonID should be 'public/protected virtual' or 'protected internal virtual'
NHibernateTest.Domain.Persons: method get_PersonName should be 'public/protected virtual' or 'protected internal virtual'
NHibernateTest.Domain.Persons: method set_PersonName should be 'public/protected virtual' or 'protected internal virtual'
Step 5.在Mapping資料夾底下加入Persons類別的描述檔.xml
檔名命名規則:類別名稱.hbm.xml(hbm為Hibernate Mapping縮寫)
為了讓此份xml有NHibernate相關的intellisense,從右上角的屬性加入結構描述檔,位置在NHibernate-3.3.1.GA-bin\Required_Bins\nhibernate-mapping.xsd
此xml的建置動作和輸出目錄跟剛剛的不太一樣
xml設定字串可以參考官方文件http://nhforge.org/doc/nh/en/index.html的4.4. Dynamic models章節
這裡從簡設定
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernateDemo"
namespace="NHibernateDemo.Domain">
<!--assembly和namespace記得填專案名稱-->
<class name="Persons">
<!--主鍵-->
<id name="PersonID" >
<generator class="identity" />
</id>
<property name="PersonName" />
</class>
</hibernate-mapping>
Step 6.加入一個類別MyHibernateHelper.cs 來初始化SessionFactory
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/*引用以下的命名空間*/
using NHibernate;
using NHibernate.Cfg;
using NHibernateDemo.Domain;
namespace NHibernateDemo
{
//class前面追加public
public class MyHibernateHelper
{
private static ISessionFactory _sessionFactory;
public static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
Configuration configuration = new Configuration();
configuration.Configure();//預設抓目錄下的hibernate.cfg.xml
//或者給絕對路徑↓
//configuration.Configure(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)+@"\hibernate.cfg.xml");
configuration.AddAssembly(typeof(Persons).Assembly);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
}
Step 7.前置作業告一段落,可以開始存取資料庫了
新增一筆資料
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//引用以下命名空間
using NHibernate;
using NHibernateDemo.Domain;
namespace NHibernateDemo
{
class Program
{
static void Main(string[] args)
{
using (ISession session = MyHibernateHelper.SessionFactory.OpenSession())
{
using (ITransaction trans = session.BeginTransaction())
{
Persons p = new Persons();
p.PersonName = "測試";
object obj = session.Save(p);//如果有設定show_sql為true的話,此句就會印出執行的SQL語句
Console.WriteLine("剛剛新增資料的主鍵:" + obj.ToString());
trans.Commit();
}//交易失敗會自動Rollback
}
Console.ReadKey();//暫停畫面用
}
}
}
查詢資料
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//引用以下命名空間
using NHibernate;
using NHibernate.Criterion;
using NHibernateDemo.Domain;
namespace NHibernateDemo
{
class Program
{
static void Main(string[] args)
{
using (ISession session = MyHibernateHelper.SessionFactory.OpenSession())
{
int[] iCondition = { 1, 2 };//條件陣列
//一般用法
//var result = session.QueryOver<Persons>().Where(x=>x.PersonID==1).List();
//var result = session.QueryOver<Persons>().Where(x => (x.PersonID >= 1 && x.PersonID <= 2)).List();
//Like用法
//var result = session.QueryOver<Persons>().Where(x => x.PersonName.IsLike("測試", MatchMode.Anywhere)).List();
//in 的用法
var result = session.QueryOver<Persons>().Where(x => x.PersonID.IsIn(iCondition)).List();
//not in 用法
//var result = session.QueryOver<Persons>().WhereNot(x => x.PersonID.IsIn(iCondition)).List();
foreach (var item in result)
{
Console.WriteLine("輸出一筆資料:"+item.PersonName);
}
}
Console.ReadKey();//暫停畫面用
}
}
}
修改資料
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//引用以下命名空間
using NHibernate;
using NHibernate.Criterion;
using NHibernateDemo.Domain;
namespace NHibernateDemo
{
class Program
{
static void Main(string[] args)
{
using (ISession session = MyHibernateHelper.SessionFactory.OpenSession())
{
using (ITransaction trans = session.BeginTransaction())
{
//找出DB的資料來Update
var result = session.QueryOver<Persons>().Where(x => x.PersonID.IsIn(new[] { 1, 2 })).List();
foreach (var item in result)
{
item.PersonName = "已修改";
session.Update(item);//這裡不會輸出SQL
}
//或建立一個想Update的物件(NHibernate會自行依主鍵找資料Update)
//Persons p = new Persons() { PersonID = 1, PersonName = "測試" };
//session.Update(p);
trans.Commit();//這裡才會真正執行Update
}
}//交易失敗會自動rollback
Console.ReadKey();//暫停畫面用
}
}
}
刪除
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//引用以下命名空間
using NHibernate;
using NHibernate.Criterion;
using NHibernateDemo.Domain;
namespace NHibernateDemo
{
class Program
{
static void Main(string[] args)
{
using (ISession session = MyHibernateHelper.SessionFactory.OpenSession())
{
using (ITransaction trans = session.BeginTransaction())
{
//找出DB的資料來Delete
var result = session.QueryOver<Persons>().Where(x => x.PersonID.IsIn(new[] { 1,2 })).List();
foreach (var item in result)
{
session.Delete(item);
}
//或建立一個想Delete的物件(NHibernate會自行依主鍵來Delete)
//Persons p = new Persons() { PersonID = 2 };
//session.Delete(p);
trans.Commit();//和上方的Delete()搭配才會輸出SQL
}//交易失敗會自動Rollback
}
Console.ReadKey();//暫停畫面用
}
}
}
結語
本文只是讓初學者快速上手的懶人文章,基本操作大概如此
不過
如果您還沒使用過NHibernate,我會告訴您,這套很搞綱,導入專案會拖慢寫Code速度
微軟的Entity Framework已經很夠用,簡單好上手,請愛用自家人產品Entity Framework
真人Live Demo:
1. C# NHibernate 3.3 Setting up
2. C# NHibernate 3.3 Domain, Mapping and NHibernate Helper
3. C# NHibernate 3.3 CRUD Functionality
官網設定檔教學:
NHibernate Configuration - NHibernate blog - NHibernate Forge