• 一个使用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 : 未能找到文件“NHibernateSampleNHibernateSample.Data.TestinDebughibernate.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 共享里下载!(关于博主的其他示例代码,也都在共享里。)

  • 相关阅读:
    linux基础学习6
    Linux基础学习5
    Linux基础学习4
    Linux基础学习3
    Linux基础学习2
    ASP.NET MVC学习——控制器传递数据到view的简单案例
    转载:URL链接中的不同用处
    MVC学习的心路历程
    45道SQL数据题详细超基础解析
    结束基础,开始MVC之旅!
  • 原文地址:https://www.cnblogs.com/tianxinbest/p/3269897.html
Copyright © 2020-2023  润新知