[C#/NHibernate] 10分鐘快速體驗NHibernate

[C#/NHibernate] 10分鐘快速體驗NHibernate

最近聽聞專案存取資料庫技術使用的是NHibernate,趕緊趁開工前Study了一下

 

前言

NHibernate是一套用物件操作方式存取資料庫的Framework

本文以Console專案(.Net4.5)搭配SQL Server Express 2012 做展示

 

實作

先自行建立一個Console專案後

 

Step 1 .接著加入相關的.dll一切才能開始

建議剛開始從官網下載壓縮包

image

本文下載的是NHibernate-3.3.1.GA-bin.zip

下載解壓後把資料夾裡Required_Bins目錄裡的Iesi.Collections.dll和NHibernate.dll加入參考

image

image

Q:為什麼不從NuGet套件安裝NHibernate呢?

A:可以是可以,但NuGet只會安裝基本用到的.dll(Iesi.Collections.dll和NHibernate.dll)

玩下去沒多久很快就會卡關,因為一開始就不知道.xml設定檔從何設定起,從官網下載的壓縮包裡面至少還有上手說明,資源較完整

 

然後還要再加入Lazy Loading會用到的.dll

NHibernate.LinFu

NHibernate.Castle

本文使用的是NHibernate.LinFu

從專案右鍵>管理NuGet套件>搜尋NHibernate.LinFu安裝

image

確認「參考」底下確實有「LinFu.DynamicProxy」、「NHibernate.ByteCode.LinFu」這兩個.dll

image

沒加入Lazy-Loading會用的.dll的話,到時候程式一執行可能發生

類型 'NHibernate.Bytecode.UnableToLoadProxyFactoryFactoryException' 的未處理例外狀況發生於 NHibernate.dll

An exception occurred in the persistence layer.

 

Step 2.加入NHibernate xml設定檔

從專案右鍵

image

image

名稱最好取名:hibernate.cfg.xml

為了要讓此xml檔可以有NHibernate相關的intellisense,從剛剛下載來的壓縮包內加入結構描述

image

image

image

整個設定字串也無須自己慢慢敲打

打開 NHibernate-3.3.1.GA-bin\HowInstall.txt檔

image

http://nhforge.org/blogs/nhibernate/archive/2008/11/09/nh2-1-0-bytecode-providers.aspx

由於本文使用的是NHibernate.LinFu

image

貼回hibernate.cfg.xml改一改

並確認複製到輸出目錄為「永遠複製」

image

image

 

Step 3. 為專案加入兩個資料夾:Domain、Mapping

image

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'

image

Step 5.在Mapping資料夾底下加入Persons類別的描述檔.xml

image

檔名命名規則:類別名稱.hbm.xml(hbm為Hibernate Mapping縮寫)

為了讓此份xml有NHibernate相關的intellisense,從右上角的屬性加入結構描述檔,位置在NHibernate-3.3.1.GA-bin\Required_Bins\nhibernate-mapping.xsd

image

此xml的建置動作和輸出目錄跟剛剛的不太一樣

image

xml設定字串可以參考官方文件http://nhforge.org/doc/nh/en/index.html4.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();//暫停畫面用
        }
    }
}

image

查詢資料


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();//暫停畫面用
        }
    }
}

image

修改資料


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();//暫停畫面用
        }
    }
}

image

刪除


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();//暫停畫面用
        }
    }
}

image

 

結語

本文只是讓初學者快速上手的懶人文章,基本操作大概如此

不過

如果您還沒使用過NHibernate,我會告訴您,這套很搞綱,導入專案會拖慢寫Code速度

微軟的Entity Framework已經很夠用,簡單好上手,請愛用自家人產品Entity Framework

比较NHibernate和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