1. 程式人生 > >Asp.net MVC + NHibernate 增刪改查簡單示例

Asp.net MVC + NHibernate 增刪改查簡單示例

一、NHibernate簡介

  什麼是?NHibernate?NHibernate是一個面向.NET環境的物件/關係資料庫對映工具。物件/關係資料庫對映(object/relational mapping,ORM)這個術語表示一種技術,用來把物件模型表示的物件對映到基於SQL的關係模型資料結構中去。

  在今日的企業環境中,把面向物件的軟體和關係資料庫一起使用可能是相當麻煩和浪費時間的。而NHibernate不僅僅管理.NET類到資料庫表的對映(包括.NET 資料型別到SQL資料型別的對映),還提供資料查詢和獲取資料的方法,可以大幅度減少開發時人工使用SQL和ADO.NET處理資料的時間。

  NHibernate的目標主要是用於與資料持久化相關的程式設計任務,能夠使開發人員從原來枯燥的SQL語句的編寫中解放出來,解放出來的精力可以讓開發人員投入到業務邏輯的實現上。對於以資料為中心的程式,開發人員往往是在資料庫中使用儲存過程來實現商業邏輯,這種情況下NHibernate可能不是最好的解決方案,但對於那些基於.NET,並且能夠實現OO業務模型和商業邏輯的中間層應用,NHibernate是最有用的。NHibernate可以幫助使用者消除或者包裝那些針對特定廠商的SQL程式碼,並且幫使用者把結果集從表格式的表示形式轉換成一系列的物件。   

  NHibernate是一個目前應用的最廣泛的開放原始碼的物件關係對映框架,它對Java的JDBC(類似於ADO.Net)進行了非常輕量級的物件封裝,使得程式設計師可以隨心所欲的使用物件程式設計思維來操縱資料庫,目前在國內Java開發界已經頗為流行,Hibernate+Spring往往是很多Java公司招聘的要求。而NHibernate,顧名思義,如同NUnit,NAnt一樣,是基於.Net的Hibernate實現,但是目前介紹NHibernate的資料非常少,缺少一個系統完整的教程來全面的展現和深入NHibernate,而且現在NHibernate的文件又殘缺不全,少的可憐,很多NHibernate的學習者往往都是通過Hibernate的文件來學習,但是畢竟不是所有的.Net開發者都熟悉Java,也不是所有的人都有精力有時間去學習Java,所以,我準備開始一個Step by Step的NHibernate教程,以便有興趣的朋友能夠快速的熟悉NHibernate,能夠更快地體驗NHibernate的開發樂趣。   

  NHibernate 是一個基於.Net 的針對關係型資料庫的物件持久化類庫。NHibernate 來源於非常優秀的基於Java的Hibernate 關係型持久化工具。   

  NHibernate 從資料庫底層來持久化你的.Net 物件到關係型資料庫。NHibernate 為你處理這些,遠勝於你不得不寫SQL去從資料庫存取物件。你的程式碼僅僅和物件關聯,NHibernat 自動產生SQL語句,並確保物件提交到正確的表和欄位中去。

二、ORM簡介

  什麼是ORM?物件-關係對映(Object/Relation Mapping,簡稱ORM),是隨著面向物件的軟體開發方法發展而產生的。面向物件的開發方法是當今企業級應用開發環境中的主流開發方法,關係資料庫是企業級應用環境中永久存放資料的主流資料儲存系統。物件和關係資料是業務實體的兩種表現形式,業務實體在記憶體中表現為物件,在資料庫中表現為關係資料。記憶體中的物件之間存在關聯和繼承關係,而在資料庫中,關係資料無法直接表達多對多關聯和繼承關係。因此,物件-關係對映(ORM)系統一般以中介軟體的形式存在,主要實現程式物件到關係資料庫資料的對映。   

  面向物件是從軟體工程基本原則(如耦合、聚合、封裝)的基礎上發展起來的,而關係資料庫則是從數學理論發展而來的,兩套理論存在顯著的區別。為了解決這個不匹配的現象,物件關係對映技術應運而生。   

  讓我們從O/R開始。字母O起源於”物件”(Object),而R則來自於”關係”(Relational)。幾乎所有的程式裡面,都存在物件和關係資料庫。在業務邏輯層和使用者介面層中,我們是面向物件的。當物件資訊發生變化的時候,我們需要把物件的資訊儲存在關係資料庫中。

  如果開啟你最近的程式(如,PetShop4.0),看看DAL(資料庫訪問層)程式碼,你肯定會看到很多近似的通用的模式。我們以儲存物件的方法為例,你傳入一個物件,為SqlCommand物件新增SqlParameter,把所有屬性和物件對應,設定SqlCommand的CommandText屬性為儲存過程,然後執行SqlCommand。對於每個物件都要重複的寫這些程式碼。除此之外,還有更好的辦法嗎?有,引入一個O/R Mapping。實質上,一個O/R Mapping會為你生成DAL。與其自己寫DAL程式碼,不如用O/R Mapping。你用O/R Mapping儲存,刪除,讀取物件,O/R Mapping負責生成SQL,你只需要關心物件就好。

三、NHiberante的優缺點

  3.1 優點

  (1).面向物件:NHiberante的使用時只需要操縱物件,使開發更物件化,拋棄了資料庫中心的思想,完全的面向物件思想。

  (2).透明持久化:帶有持久化狀態的、具有業務功能的單執行緒物件,此物件生存期很短。這些物件可能是普通的POCO,這個物件沒有實現第三方框架或者介面,唯一特殊的是他們正與(僅僅一個)Session相關聯。一旦這個Session被關閉,這些物件就會脫離持久化狀態,這樣就可被應用程式的任何層自由使用。(例如,用作跟表示層打交道的資料傳輸物件。)

  (3).它沒有侵入性,即所謂的輕量級框架。正因為它具有透明持久化的優點,它才沒有侵入性,才是一個輕量級框架。恆定一個框架為重量級、還是輕量級,是根據其侵入性而定奪的。而NHibernate就是一個輕量級ORM框架。

  (4).較好的移植性:支援多種資料庫,便於資料庫的遷移。

  (5).快取機制:提供一、二級快取和查詢快取。

  (6).開發效率:眾所周知,使用NHibernate可以簡化程式開發,從而達到快速開發的目的。作為軟體公司,專案管理的關鍵就是控制開發成本。正因為使用NHibernate後所寫的程式碼量減少了,相對於原先使用“SqlHelper、DAL、BLL”開發程式的專案週期縮短了,成本就降低了。

  3.2 缺點

  (1).記憶體消耗:直接使用“SqlHelper、DAL、BLL”無疑是最省記憶體的。使用NHibernate後,記憶體開銷比較大,這點是毋庸置疑的。

  (2).批量資料庫的處理:由於NHibernate是基於面向物件的ORM框架,處理資料庫的方式是針對單個物件的。對資料庫的增、刪、改都是正對一條記錄而言。對於批量修改、刪除資料,不適合用NHiberante。這也是所有OR框架弱點,其原因,我認為是在於與快取機制的衝突。

  (3).較多使用資料庫特性時,也不適合使用NHiberante。如資料庫中大量的儲存過程、觸發器、特點的SQL語句。

  (4).表關係比較混亂時也不適合使用NHiberante。NHibernate只適合於表與表的關係比較明確的環境中。如本應該建立外來鍵的,沒有建立外來鍵。這時使用NHiberante不僅沒有減少工作量,反而增加了工作量。

  (5).學習成本:相對於NHibernate來說,使用“SqlHelper、DAL、BLL”操作資料庫,學習成本比較低,而且上手很快。使用NHibernate需要有一定OOP(面向物件程式設計)和OOD(面向物件設計)的基礎,這對於基礎薄弱的程式設計師來說,從面向過程的程式設計到面向物件的程式設計,需要一定的投入;一般情況下需要學習1個月左右的時間才能夠深入NHiberante。

四、簡單增刪改查

1、建立MVC專案,並建立相關類

這裡寫圖片描述

這裡寫圖片描述

2、安裝NHibernate4.0

這裡寫圖片描述

3、配置NHibernate

將下圖中花圈的檔案複製到Shop.Web專案中,放在主目錄下面,因為我使用的是Sql Server
然後重新命名為Hibernate.cfg.xml
這裡寫圖片描述

為Hibernate.cfg.xml檔案新增mapping節點

<?xml version="1.0" encoding="utf-8"?>
<!-- 
This template was written to work with NHibernate.Test.
Copy the template to your NHibernate.Test project folder and rename it in hibernate.cfg.xml and change it 
for your own use before compile tests in VisualStudio.
-->
<!-- This is the System.Data.dll provider for SQL Server -->
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
    <session-factory name="NHibernate.Test">
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
        <property name="connection.connection_string">
      Server=.\MSSQL2008R2;database=TEST;uid=sa;pwd=123456
    </property>
    <!--NHibernate方言(Dialect)的類名 - 可以讓NHibernate使用某些特定的資料庫平臺的特性-->
    <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
    <!--在控制檯顯示SQL-->
    <property name="show_sql">true</property>
    <!--指定對映文件中所在程式集-->
    <mapping  assembly="Shop.Domain"/>
    </session-factory>
</hibernate-configuration>

修改Hibernate.cfg.xml檔案屬性為始終複製或者如果較新則複製
這裡寫圖片描述

4、在Shop.Data專案中建立NHibernateHelper幫助類
這裡寫圖片描述

namespace Shop.Data
{
    public class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;

        public static ISessionFactory SessionFactory
        {
            get
            {
                //配置ISessionFactory
                return _sessionFactory == null ? (new Configuration()).Configure().BuildSessionFactory() : _sessionFactory;
            }
        }
    }
}

5、在Shop.Domain專案中建立Customers實體類

namespace Shop.Domain.Entities
{
    public class Customers
    {
        public virtual int CustomerID { get; set; }
        public virtual string CompanyName { get; set; }
        public virtual string ContactName { get; set; }
        public virtual string ContactTitle { get; set; }
        public virtual string Address { get; set; }
        public virtual string City { get; set; }
        public virtual string Region { get; set; }
        public virtual string PostalCode { get; set; }
        public virtual string Country { get; set; }
        public virtual string Phone { get; set; }
        public virtual string Fax { get; set; }

    }
}

6、在Shop.Domain專案中新建Customers.hbm.xml作為Customers持久化類的對映檔案

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Shop.Domain" namespace="Shop.Domain.Entities">
  <class name="Shop.Domain.Entities.Customers,Shop.Domain" table="Customers">
    <id name="CustomerID" column="CustomerID" type="int"></id>
    <property name="CompanyName" column="CompanyName" type="string"></property>
    <property name="ContactName" column="ContactName" type="string"></property>
    <property name="ContactTitle" column="ContactTitle" type="string"></property>
    <property name="Address" column="Address" type="string"></property>
    <property name="City" column="City" type="string"></property>
    <property name="Region" column="Region" type="string"></property>
    <property name="PostalCode" column="PostalCode" type="string"></property>
    <property name="Country" column="Country" type="string"></property>
    <property name="Phone" column="Phone" type="string"></property>
    <property name="Fax" column="Fax" type="string"></property>
  </class>
</hibernate-mapping>

這裡寫圖片描述

設定檔案屬性

這裡寫圖片描述

7、在Shop.Data中新增資料訪問類CustomersData,編寫GetCustomerList方法 獲取所有客戶列表

        public IList<Customers> GetCustomerList(Expression<Func<Customers,bool>> where)
        {
            try
            {
                using(ISession session = NHibernateHelper.SessionFactory.OpenSession())
                {
                    return session.Query<Customers>().Select(x => new Customers
                    {
                        CustomerID = x.CustomerID,
                        ContactName = x.ContactName,
                        ContactTitle = x.ContactTitle,
                        City = x.City,
                        Address = x.Address,
                        Phone = x.Phone,
                        CompanyName = x.CompanyName,
                        Country = x.Country,
                        Fax = x.Fax,
                        Region=x.Region,
                        PostalCode=x.PostalCode
                    }).Where(where).ToList();
                }
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }

8、新增業務邏輯層,在Shop.Business專案中新建CustomersBusiness類

 public class CustomersBusiness
    {
        private CustomersData _customersData;
        public CustomersBusiness()
        {
            _customersData = new CustomersData();
        }

        public IList<Customers> GetCustomersList(Expression<Func<Customers, bool>> where)
        {
            return _customersData.GetCustomerList(where);
        }
     }

9、新增控制器,新增檢視

    public class CustomersController : Controller
    {
        CustomersBusiness customersBusiness = new CustomersBusiness();
        // GET: Customers
        public ActionResult Index()
        {            
            var result = customersBusiness.GetCustomersList(c => 1 == 1);

            return View(result);
        }
    }

10、顯示結果

這裡寫圖片描述

11、增刪改查

  public Customers GetByID(int id)
        {
            using(ISession session = NHibernateHelper.SessionFactory.OpenSession())
            {
                Customers customers = session.Get<Customers>(id);
                return customers;
            }
        }
        public bool Insert(Customers customer)
        {
            using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
            {
                var identifier = session.Save(customer);
                session.Flush();
                return string.IsNullOrEmpty(identifier.ToString());
            }
        }

        public void Update(Customers customer)
        {
            using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
            {
                session.SaveOrUpdate(customer);
                session.Flush();
            }
        }
        public void Delete(int id)
        {
            using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
            {
                Customers customer = session.Get<Customers>(id);
                session.Delete(customer);
                session.Flush();
            }
        }