65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 的 NHibernate 设置

2013 年 11 月 27 日

CPOL

11分钟阅读

viewsIcon

97751

downloadIcon

2115

了解如何在 ASP.NET 应用程序中配置 NHibernate

引言

NHibernate 是一个相当流行的框架,用于抽象和处理持久化层。即使在今天,随着 Entity Framework 的出现,NHibernate 因其成熟度和资源丰富性,仍然是许多开发者的首选。

本文旨在提供一个基本的 ASP.NET 应用程序,作为任何希望从零开始开发的人的基础。本文提供了这个基本应用程序,其中包含一个小实体,并详细解释了 NHibernate 是如何在应用程序中设置的。

以下是成功设置 NHibernate 所需执行的步骤:

  1. 创建一个空白的 ASP.NET 项目。
  2. 通过 NuGet 导入所需的 DLL。
  3. 创建用于创建和处理 NHibernate 会话和操作的类。
  4. Web.Config 文件中配置 NHibernateLog4net。可选地,Log4net 可以记录 NHibernate 的日志,这将在本文中演示。
  5. Global.asax 中配置 NHibernate 会话。
  6. hbm.xml 文件中创建实体的映射,以及它们各自的值对象类文件。
  7. Web.Config 文件中,使用下载的应用程序中声明的设置创建一个数据库。该数据库连接字符串名为 DatabaseConnectionString,可以在 connectionStrings 标签中找到。

在回顾了以上主题后,将提供如何执行应用程序的简要说明。最后,本文将以对 NHibernate 及其优缺点的小讨论结束。

这里需要做一个小说明:代码完全使用 Microsoft Web Developer 2010 开发。

设置 NHibernate

创建空白项目并导入所需 DLL

为了开始开发,需要创建一个空的 ASP.NET 空 Web 应用程序,通过 NuGet 导入所需的 DLL,并创建必要的文件。由于这些步骤非常直接,而且不是本文的重点,因此将不在此演示。本文提供的示例可下载项目可作为初始开发的基准模板。不过,这里有三个相关的注意事项:

  • 通过 NuGet 导入的 DLL 是:
  • 需要通过以下步骤添加对 System.Transactions 的引用:
    1. 解决方案资源管理器 中,右键单击 引用 元素,然后选择 添加引用...
    2. 选择 .NET 选项卡,然后选择 System.Transactions 项。
    3. OK,此引用将被导入到项目中。
  • 每当添加一个 hbm.xml 文件时,对于这种设置,将其设置为 嵌入资源 非常重要。这是强制性的,因为通过这样做,NHibernate 框架可以轻松找到这些资源。为此,请按照以下步骤操作:
    1. 解决方案资源管理器 中,右键单击文件,然后单击 属性
    2. 生成操作 部分,选择 嵌入资源
    3. 按 Ctrl+S 保存此配置。

处理 NHibernate 的基本类

现在项目已设置好,必须定义用于使用 NHibernate 的类。它们是 NHibernateHelperSessionHelper,均在下载项目中的 NHibernate 目录下创建。

下面是 NHibernateHelper 的代码:

using System;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Context;
 
namespace WebAppBasicNHibernate.NHibernate
{
    /// <summary>
    /// Here basic NHibernate manipulation methods are implemented.
    /// </summary>
    public class NHibernateHelper
    {
        private ISessionFactory _sessionFactory = null;
 
        /// <summary>
        /// In case there is an already instantiated NHibernate ISessionFactory,
        /// retrieve it, otherwise instantiate it.
        /// </summary>
        public ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    Configuration configuration = new Configuration();
                    configuration.Configure();
 
                    // build a Session Factory
                    _sessionFactory = configuration.BuildSessionFactory();
                }
                return _sessionFactory;
            }
        }
 
        /// <summary>
        /// Open an ISession based on the built SessionFactory.
        /// </summary>
        /// <returns>Opened ISession.</returns>
        public ISession OpenSession()
        {
            return SessionFactory.OpenSession();
 
        }
        /// <summary>
        /// Create an ISession and bind it to the current tNHibernate Context.
        /// </summary>
        public void CreateSession()
        {
            CurrentSessionContext.Bind(OpenSession());
        }
 
        /// <summary>
        /// Close an ISession and unbind it from the current
        /// NHibernate Context.
        /// </summary>
        public void CloseSession()
        {
            if (CurrentSessionContext.HasBind(SessionFactory))
            {
                CurrentSessionContext.Unbind(SessionFactory).Dispose();
            }
        }
 
        /// <summary>
        /// Retrieve the current binded NHibernate ISession, in case there
        /// is any. Otherwise, open a new ISession.
        /// </summary>
        /// <returns>The current binded NHibernate ISession.</returns>
        public ISession GetCurrentSession()
        {
            if (!CurrentSessionContext.HasBind(SessionFactory))
            {
                CurrentSessionContext.Bind(SessionFactory.OpenSession());
            }
            return SessionFactory.GetCurrentSession();
        }
    }
} 

此类通过访问 Web.Config 文件中的数据来配置 NHibernate。这是在 SessionFactory 属性中完成的。基本上,使用无参数的 Configuration.Configure() 方法,框架会从 Web.Config 文件中获取配置数据。另外请注意,会话存储在名为 _sessionFactory static ISessionFactory 对象中。每当再次调用 SessionFactory 属性时,如果已存在 _sessionFactory 对象,则不会创建新实例,因此会使用已存在的实例。请注意,这里实现了单例设计模式。这样做的原因是构建 ISessionFactory 对象成本很高,因此使用单例非常优雅。

NHibernateHelper 类中的其他方法仅用于操作会话。接下来,查看 SessionHelper 类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NHibernate;
 
namespace WebAppBasicNHibernate.NHibernate
{
    /// <summary>
    /// Helper methods for dealing with NHibernate ISession.
    /// </summary>
    public class SessionHelper
    {
        /// <summary>
        /// NHibernate Helper
        /// </summary>
        private NHibernateHelper _nHibernateHelper = null;
 
        public SessionHelper()
        {
            _nHibernateHelper = new NHibernateHelper();
        }
 
        /// <summary>
        /// Retrieve the current ISession.
        /// </summary>
        public ISession Current
        {
            get
            {
                return _nHibernateHelper.GetCurrentSession();
            }
        }
 
        /// <summary>
        /// Create an ISession.
        /// </summary>
        public void CreateSession()
        {
            _nHibernateHelper.CreateSession();
        }
 
        /// <summary>
        /// Clear an ISession.
        /// </summary>
        public void ClearSession()
        {
            Current.Clear();
        }
 
        /// <summary>
        /// Open an ISession.
        /// </summary>
        public void OpenSession()
        {
            _nHibernateHelper.OpenSession();
        }
 
        /// <summary>
        /// Close an ISession.
        /// </summary>
        public void CloseSession()
        {
            _nHibernateHelper.CloseSession();
        }
    }
} 

此类仅作为 NHibernateHelper 的包装器。您甚至可以选择不实现它,直接使用 NHibernateHelper 本身,但是您可能会发现这个包装器很有用。

在 Web.Config 中配置 NHibernate 数据库设置和 Log4Net

在基本设置完成后,需要配置 NHibernate 数据库设置,以及可选的 Log4net。由于 Web.Config 文件相当小,因此将在下面完整显示。

<?xml version="1.0"?>
 
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
 
<configuration>
    <configSections>
      <!-- Declaration for NHibernate and Log4Net sections -->
      <section name="hibernate-configuration" 
      type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
      <section name="log4net" 
      type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
    </configSections>
    <connectionStrings>
      <add name="DatabaseConnectionString" 
         connectionString="User ID=eduardo;Password=eduardo;
           Data Source=.\SQLExpress; Initial Catalog=NHibernateBasic" />
    </connectionStrings>
    <!-- Log4Net config -->
    <log4net>
      <logger name="WebAppBasicNHibernateLogger">
        <level value="ALL" />
        <appender-ref ref="LogFileAppender" />
      </logger>
      <logger name="NHibernate.SQL">
        <level value="DEBUG" />
        <appender-ref ref="LogFileAppender" />
      </logger>
      <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
        <file type="log4net.Util.PatternString" 
        value="c:\LogWebAppBasicNHibernate\Log-" />
        <appendToFile value="true" />
        <rollingStyle value="Composite" />
        <maxSizeRollBackups value="25" />
        <maximumFileSize value="20MB" />
        <datePattern value="yyyy-MM-dd'.log'" />
        <staticLogFileName value="false" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
        </layout>
      </appender>
    </log4net>
    <!-- NHibernate configuration -->
    <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_name">DatabaseConnectionString</property>
        <property name="show_sql">true</property>
        <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
        <!-- Create Database -->
        <property name="hbm2ddl.auto">update</property>
        <property name="current_session_context_class">web</property>
        <mapping assembly="WebAppBasicNHibernate" />
      </session-factory>
    </hibernate-configuration>
  
    <system.web>
        <customErrors mode="Off"/>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
 
</configuration> 

configSections 标签中,可以看到 NHibernateLog4net 部分的声明。另外,请注意,在 connectionStrings 标签中有一个名为 DatabaseConnectionString 的连接字符串,它用于 NHibernate 数据库配置。

如果查看 log4net 标签,您会看到 Log4net 的配置设置。名为 WebAppBasicNHibernateLogger 的日志记录器用于记录应用程序的事件,而 NHibernate.SQL 用于记录 NHibernate 的事件。请注意,NHibernate.SQL 的调试级别设置为 DEBUG,这将记录所有运行的查询。最后,为此,请注意 WebAppBasicNHibernateLogger NHibernate.SQL 都使用 LogFileAppender 作为其日志记录机制,该机制基本上将数据记录到磁盘文件,其设置位于其配置中。

hibernate-configuration 标签之间可以找到 NHibernate 的设置。可以看到使用了 DatabaseConnectionString ,选择了 Microsoft SQL Server 方言,Assembly 名称与应用程序匹配,数据库将自动更新(因为 hbm2ddl.auto 标签设置为 update),最后 SQL 查询被配置为显示(因为 show_sql 标签设置为 true )。这是 NHibernate 配置的核心。在这里,您可以更改正在使用的连接字符串、SQL 语言、数据模型的程序集、数据库的更新方式等等。因此,请特别注意这些设置,并学会如何正确更改它们。

最后,需要强调的是,要运行可下载的应用程序,必须创建一个数据库,其设置与此连接字符串 DatabaseConnectionString 中声明的设置相符。请注意,您可以根据需要更改这些设置。此外,可下载应用程序已使用 SQL Server 2008 Express Edition 进行测试。

在 Global.asax 中设置 NHibernate 会话

这可能是 NHibernate 设置中最关键的部分。如果选择对实体使用 延迟加载,则必须在此处相应地使用会话的打开和关闭。

为了支持 延迟加载NHibernate 需要在请求开始时打开 Session ,并在请求结束时关闭它。因此,Global.asax 是执行此操作的正确位置,因为它捕获了请求打开和关闭的所有事件。下面显示了执行上述操作的代码:

protected SessionHelper _sessionHelper = null;
 
..............
 
protected void Application_BeginRequest(object sender, EventArgs e)
{
	_sessionHelper = new SessionHelper();
	_sessionHelper.OpenSession();
}
 
protected void Application_EndRequest(object sender, EventArgs e)
{
	_sessionHelper = new SessionHelper();
	_sessionHelper.CloseSession();
}

请注意,在 Global.asax 文件中设置 NHibernateSession 是多么直接,对于 延迟加载 来说。只需捕获请求开始事件,打开会话,捕获请求结束事件,最后关闭 Session 。请注意,每次打开或关闭 Session 时都会创建一个新对象,但这对于性能无关紧要,因为 ISessionFactory 本身在 NHibernateHelper 类中被视为单例。

最后一点是关于 Log4net,它在应用程序启动时进行初始化,如下所示:

protected void Application_Start(object sender, EventArgs e)
{
	// start log4net
	XmlConfigurator.Configure();
	
	....
} 

到这里就可以结束阅读本文了,因为关于设置 NHibernate 所需的一切都已解释清楚。接下来将展示如何创建 NHibernate 实体、数据访问对象 (DAO),以及讨论一些其他有趣的话题。

创建从数据库映射的实体

为了开始使用 NHibernate,首先需要创建将数据库表映射到值对象的实体。为此,需要创建一个类来表示值对象,并将其映射到 XML 文件中,通常命名为:FILE_NAME.hbm.xml 。这里将重复本文中已经说过的一点:hbm.xml 文件必须配置为嵌入资源,应用程序才能按本文所述工作。

下载的应用程序附带了一个小机制,可以在创建实体和数据访问对象 (DAO) 时重用代码。这个机制,正如将要演示的那样,非常简单,但可以节省大量的编码工作。下面是它的类图:

UML diagram of VO/DAO NHibernate mechanism

基本上,该机制使用了两个类:BaseVo BaseDao 。所有实体都应继承自 BaseVo ,所有数据访问对象 (DAO) 都应继承自 BaseDao BaseVo 包含 Id 属性,该属性用作所有实体的标识符。其类型是泛型的,因此在 BaseVo 子类化时定义。将此 Id 放在基类中,可以避免每个实体都定义其标识符的需要。此外,BaseVo 及其标识符在 BaseDao 中使用,后者实现了对所有 NHibernate 数据访问对象都有用的方法。通过让所有 DAO 继承自基类,所有这些方法都可以重用。

由于本文仅旨在描述基本的 NHibernate 设置,因此这里将只创建一个实体及其映射,并提供一些数据库交互的示例:Person PersonDao ,正如您在类图中看到的。

现在,看一下 BaseVo 类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
 
namespace WebAppBasicNHibernate.Vo
{
    /// <summary>
    /// Base Value Object class.
    /// </summary>
    /// <typeparam name="TIdentifier">Identifier Generic Type to be assigned dynamically.</typeparam>
    public class BaseVo<TIdentifier> 
        where TIdentifier : new()
    {
        /// <summary>
        /// Gets or sets the Identifier.
        /// </summary>
        public virtual TIdentifier Id { get; set; }
    }
} 

请注意此类多么直接。也请注意泛型标识符的使用。接下来,看一下 BaseDao 类:

using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using NHibernate;
using NHibernate.Linq;
using WebAppBasicNHibernate.NHibernate;
using WebAppBasicNHibernate.Vo;
 
namespace WebAppBasicNHibernate.Dao
{
    public class BaseDao<TEntity, TIdentifier>
        where TIdentifier : new()
        where TEntity : BaseVo<TIdentifier> 
    {
        /// <summary>
        /// NHibernate ISession to be used to manipulate data in the
        /// database.
        /// </summary>
        protected ISession CurrentSession { get; set; }
 
        public BaseDao()
        {
            SessionHelper sessionHelper = new SessionHelper();
            CurrentSession = sessionHelper.Current;
        }
 
        /// <summary>
        /// Load an Entity by its identifier.
        /// </summary>
        /// <param name="id">Entity´s identifier.</param>
        /// <returns>Entity Object.</returns>
        public TEntity LoadById(TIdentifier id)
        {
            TEntity entity = CurrentSession.Get<TEntity>(id);
            return entity;
        }
 
        /// <summary>
        /// Create an Entity.
        /// </summary>
        /// <param name="entity">Entity to be created.</param>
        /// <returns>Identifier of the created Entity.</returns>
        public TIdentifier Create(TEntity entity)
        {
            TIdentifier identifier = new TIdentifier();
            using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required))
            {
                identifier = (TIdentifier)CurrentSession.Save(entity);
                transaction.Complete();
            }
            return identifier;
        }
 
        /// <summary>
        /// Save or Update an Entity.
        /// </summary>
        /// <param name="entity">Entity to be saved or updated.</param>
        public void SaveOrUpdate(TEntity entity)
        {
            TIdentifier identifier = new TIdentifier();
            using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required))
            {
                CurrentSession.SaveOrUpdate(entity);
                transaction.Complete();
            }
        }
 
        /// <summary>
        /// Update an existing Entity.
        /// </summary>
        /// <param name="entity">Entity to be updated.</param>
        public void Update(TEntity entity)
        {
            using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required))
            {
                CurrentSession.Update(entity);
                CurrentSession.Flush();
                transaction.Complete();
            }
        }
 
        /// <summary>
        /// Delete an Entity based on its Instance.
        /// </summary>
        /// <param name="entity">Entity Instance.</param>
        public void Delete(TEntity entity)
        {
            using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required))
            {
                CurrentSession.Delete(entity);
                transaction.Complete();
            }
        }
 
        /// <summary>
        /// Delete an Entity based on its Identifier.
        /// </summary>
        /// <param name="entityIdentifier">Entity Identifier.</param>
        public void DeleteById(TIdentifier entityIdentifier)
        {
            using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required))
            {
                TEntity entity = LoadById(entityIdentifier);
                CurrentSession.Delete(entity);
                transaction.Complete();
            }
        }
 
        /// <summary>
        /// Retrieve all Entities from the database.
        /// </summary>
        /// <returns>List of all entities.</returns>
        public IList<TEntity> LoadAll()
        {
            return CurrentSession.Query<TEntity>().ToList();
        }
    }
}  

请注意此类如何使用泛型来收集实体标识符和实体本身。另请参阅实体泛型必须继承自 BaseVo ,这使得该机制更加健壮。此外,许多有用的方法都是使用 NHibernate API 实现的,并结合泛型实体和标识符。每当一个类继承自 BaseDao 时,这些泛型值将自动填充,并且方法将对该类非常有用。

最后,请看下面的 Person PersonDao

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
 
namespace WebAppBasicNHibernate.Vo
{
    public class Person : BaseVo<Int64>
    {
        public virtual String Name { get; set; }
        public virtual Int32 Age { get; set; }
    }
}
using System;
using WebAppBasicNHibernate.Vo;
using System.Collections.Generic;
using NHibernate.Linq;
 
namespace WebAppBasicNHibernate.Dao
{
    public class PersonDao : BaseDao<Person, Int64>
    {
        public void DeleteByName(String name)
        {
            var queryResult = CurrentSession.QueryOver<Person>()
                              .Where(p => p.Name == name);
 
            if (queryResult != null && queryResult.RowCount() > 0)
            {
                IList<Person> peopleToBeDeleted = queryResult.List();
                peopleToBeDeleted.ForEach(personToBeDeleted => CurrentSession.Delete(personToBeDeleted));
                CurrentSession.Flush();
            }
        }
    }
} 

请注意节省了多少代码,因为 PersonDao 只有一个已实现的方法,但具有几个自动继承的方法。

Person.hbm.xml 文件也很重要,下面将显示它:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
   namespace="WebAppBasicNHibernate.Vo" assembly="WebAppBasicNHibernate">
 
  <class name="Person" table="PERSON" >
 
    <!-- Primary Key(s) -->
    <id name="Id" column="ID">
      <generator class="identity" />
    </id>
 
    <property name="Name" column="NAME" not-null="true" />
    <property name="Age" column="AGE" not-null="true" />
 
  </class>
</hibernate-mapping> 

请注意将表列映射到对象属性。另请注意表定义。需要注意的一个重要细节是应用程序命名空间的使用。

设置好实体及其数据访问对象后,就可以进行一些数据库操作了。这将在下一节中讨论。

数据库交互示例

下载的应用程序包含一些 NHibernate 用法的示例。本节将演示它们。下面显示了 Global.asax 的完整代码。请注意,在 Application_Start 事件中,执行了一系列 NHibernate 数据库操作。创建了三个实体,删除了一个。此外,请注意使用默认的 Microsoft .NET 事务。这是允许的,并且使用此事务与使用 NHibernate 提供的事务之间没有区别。公平地说,NHibernate 事务有一个巨大的缺点:它不能嵌套在另一个 NHibernate 事务中。这会使事情变得复杂,因为当一个方法调用另一个方法时,必须小心检查它们是否都只使用一个 NHibernate 事务。

另一项重要声明:Application_Start 事件仅在应用程序启动时执行。要再次执行它,必须重新启动 Internet Information Services (IIS)。

using System;
using System.Collections.Generic;
using System.Transactions;
using log4net;
using log4net.Config;
using WebAppBasicNHibernate.Dao;
using WebAppBasicNHibernate.NHibernate;
using WebAppBasicNHibernate.Vo;
 
namespace WebAppBasicNHibernate
{
    public class Global : System.Web.HttpApplication
    {
        protected SessionHelper _sessionHelper = null;
 
        private static ILog _log = 
          LogManager.GetLogger(Log4NetConstants.WEB_APP_BASIC_NHIBERNATE_LOGGER);
 
        protected void Application_Start(object sender, EventArgs e)
        {
            // start log4net
            XmlConfigurator.Configure();
 
            try
            {
 
                _sessionHelper = new SessionHelper();
                _sessionHelper.OpenSession();
 
                using (TransactionScope transactionScope = new TransactionScope())
                {
                    PersonDao personDao = new PersonDao();
 
                    // delete all people, in case there are any
                    IList<Person> people = personDao.LoadAll();
                    if (people != null && people.Count > 0)
                    {
                        foreach (Person person in people)
                        {
                            personDao.Delete(person);
                        }
                    }
 
                    // create three people
                    Person jose = new Person();
                    jose.Name = "Jose";
                    jose.Age = 28;
                    personDao.SaveOrUpdate(jose);
 
                    Person maria = new Person();
                    maria.Name = "Maria";
                    maria.Age = 29;
                    personDao.SaveOrUpdate(maria);
 
                    Person mario = new Person();
                    mario.Name = "Mario";
                    mario.Age = 27;
                    personDao.SaveOrUpdate(mario);
 
                    // delete Mario
                    personDao.Delete(mario);
 
                    transactionScope.Complete();
                }
 
                _sessionHelper.CloseSession();
 
            }
            catch (Exception ex)
            {
                _log.Error("An error has occurred while initializing the application.", ex);
            }
        }
 
        protected void Session_Start(object sender, EventArgs e)
        {
 
        }
 
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            _sessionHelper = new SessionHelper();
            _sessionHelper.OpenSession();
        }
 
        protected void Application_EndRequest(object sender, EventArgs e)
        {
            _sessionHelper = new SessionHelper();
            _sessionHelper.CloseSession();
        }
 
        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {
 
        }
 
        protected void Application_Error(object sender, EventArgs e)
        {
 
        }
 
        protected void Session_End(object sender, EventArgs e)
        {
            
        }
 
        protected void Application_End(object sender, EventArgs e)
        {
 
        }
    }
} 

Default.aspx.cs 中可以看到另一个示例。这里执行了更多的 NHibernate 数据库操作。请注意使用了 NHibernate 事务。请记住,对于这种事务,不能有嵌套的异常。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using WebAppBasicNHibernate.Vo;
using WebAppBasicNHibernate.Dao;
using log4net;
using NHibernate;
using WebAppBasicNHibernate.NHibernate;
 
namespace WebAppBasicNHibernate
{
    public partial class Default : System.Web.UI.Page
    {
        private static ILog _log = 
           LogManager.GetLogger(Log4NetConstants.WEB_APP_BASIC_NHIBERNATE_LOGGER);
 
        protected void Page_Load(object sender, EventArgs e)
        {
 
        }
 
        private void ManipulatePerson()
        {
            try
            {
                SessionHelper sessionHelper = new SessionHelper();
                using (ITransaction transaction = sessionHelper.Current.BeginTransaction())
                {
                    PersonDao personDao = new PersonDao();
                    // remove John and Mary
                    personDao.DeleteByName("John");
                    personDao.DeleteByName("Mary");
 
                    _log.Info("Removed John and Mary, in case they do exist");
                    lblOperations.Text = "Removed John and Mary, in case they do exist";
 
                    // create john
                    Person john = new Person();
                    john.Name = "John";
                    john.Age = 32;
 
                    personDao.SaveOrUpdate(john);
 
                    _log.Info("Created John.");
                    lblOperations.Text += "<br>Created John.";
 
                    // create mary
                    Person mary = new Person();
                    mary.Name = "Mary";
                    mary.Age = 33;
 
                    personDao.SaveOrUpdate(mary);
 
                    _log.Info("Created Mary.");
                    lblOperations.Text += "<br>Created Mary.";
 
                    transaction.Commit();
                }
            }
            catch (Exception ex)
            {
                // log exception in case any errors occur
                _log.Error("Error while manipulating entities using NHibernate.", ex);
            }
        }
 
        protected void btnExecuteNHibernateOperations_Click(object sender, EventArgs e)
        {
            // execute operations with NHibernate
            ManipulatePerson();
        }
    }
} 

这结束了代码解释。请不要忘记创建数据库以运行此应用程序。配置如前所述,在 Web.Config 文件中设置。

运行代码

项目编译和执行非常简单:

  1. 使用 Microsoft Visual Web Developer 2010 或更高版本打开项目。当然,您也可以使用 Visual Studio。
  2. 编译项目。请注意,第一次时,所有必需的库都将通过 NuGet 自动下载。
  3. 运行项目。

当项目运行时,数据库表将被创建,并且 Global.asax 中的操作仅在软件启动时执行。如前所述,只有当您重新启动 Internet Information Services (IIS) 时,它们才会再次执行。如果应用程序成功执行,将出现一个屏幕,如下所示:

如果您按下 ªExecute NHibernate Operationsª,将执行一些 NHibernate 数据库操作。这些操作已在上一节中讨论过。您可以看到结果已持久化到数据库中。

讨论

尽管本文内容广泛,但请注意,设置 NHibernate 并不复杂。基本上,需要导入所需的库,设置基本 Session 类,配置数据库,然后开始实现值对象和数据访问对象类。

NHibernate 是一个强大的框架,被 Microsoft .NET 开发者广泛使用,并且在 Java 用户中更加普及,当然是利用 Hibernate 框架。

NHibernate 之所以如此出名,是因为它节省了大量的编码时间。主要是因为它自动地将数据库数据转换为软件对象,反之亦然。它还允许开发人员在代码中构建复杂的查询,这极大地简化了软件开发和维护。

作为一个负面因素,NHibernate 的学习曲线相当陡峭,使其学习并非易事。然而,由于开发人员喜欢挑战,掌握这个框架是值得的。

Microsoft 发布了 Entity Framework,恕我直言,它是 NHibernate 的复制品,并带有可视化建模向导。即便如此,Entity Framework 的早期版本仍有很大的改进空间,这证明了构建这样一个框架的难度,以及 NHibernate 的成熟度。

通过 QueryOver API,NHibernate 仍然比 Entity Framework 更易于使用,并且即使到目前为止,在与 Microsoft SQL Server 以外的其他数据库一起使用时,它也更可靠。

总而言之,NHibernate 是一个伟大的框架,希望它能继续存在很多年。

© . All rights reserved.