一個使用MVC3+NHibernate “增刪改查” 的項目(修正版)


        

  前言:

談到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開發)

  1. 添加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; }
    }
Users類

      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>
Users.hbm.xml

           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>
hibernate.cfg.xml

 

創建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();
        }
    }
NHibernateHelper.cs 
               
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);
        }
    }
NHibernateRepository.cs
               
    public class UsersRepository: NHibernateRepository<Users, int>
    {

    }
UsersRepository.cs 
               
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);
    }
IRepository 實現增刪改查的接口

         (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(); 
            }
        }
Global.asax.cs 

                 NHibernate的查詢:

     分為以下幾種:(我在項目中用的第三種方式(Linq))

  1. HQL: NHibernate配備了一種非常強大的查詢語言,這種語言看上去很像SQL。但是不要被語法結構 上的相似所迷惑, HQL是非常有意識的被設計為完全面向對象的查詢,它可以理解如繼承、多態 和關聯之類的概念。   

              
return _session.CreateQuery("from Customer c where c.Firstname=:fn")
        .SetString("fn", firstname)
        .List<Customer>();
HQL寫法 

      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>();
}
Criteria Query寫法

      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;
        }
Linq寫法

根據前面的總結,很容易的可以在項目中使用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 共享里下載!(關於博主的其他示例代碼,也都在共享里。)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM