Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

NHibernate Setup for ASP.NET

7 Jul 2014 1  
Learn how to configure NHibernate on your ASP.NET application

Introduction

NHibernate is quite a popular framework for abstracting and handling the persistence layer. Even today with Entity Framework, NHibernate is still the first choice for many developers due to its maturity and resourcefulness.

This article aims to provide a basic ASP.NET application which would serve as the basis for anyone who wishes to start the development from scratch. Here is provided this basic app with a small entity being used and a detailed explanation on how NHibernate was setup in the application.

Here are the steps one needs to execute in order to successfully setup NHibernate:

  1. Create a blank ASP.NET Project.
  2. Import the needed DLLs through NuGet.
  3. Create classes for creating and handling NHibernate sessions and operations.
  4. Configure NHibernate and Log4net in the Web.Config file. Optionally Log4net can log NHibernate and this will be demonstrated in this article.
  5. Configure NHibernate session in Global.asax.
  6. Create the mapping of Entities in the hbm.xml files along with their respective Value Object class files.
  7. Create a database with the settings declared in the downloadable application, in the Web.Config file. The Connection String for that is called DatabaseConnectionString and it can be found within the connectionStrings tags.

After going through the topics above, a brief explanation of how to execute the application will be provided. Finally, this article will end with a small discussion about NHibernate, its strong and weak points.

A small observation has to be made here: the code was entirely developed using Microsoft Web Developer 2010.

Setting Up NHibernate

Create a Blank Project and Import Required DLLs

In order to start the development, one needs to create an empty ASP.NET Empty Web Application, import the required DLLs via NuGet, and create the necessary files. Since this is pretty straightforward and these steps are not the focus of this article, they will not be demonstrated here. The sample downloadable project in this article can be used as a base template for the initial development. Three observations, however, are relevant here:

  • The imported DLLs via NuGet are:
  • A reference to System.Transactions needs to be added via the following steps:
    1. In the Solution Explorer, in the References element, right-click with the mouse and select Add Reference...
    2. Select the tab .NET and select the item System.Transactions
    3. Press OK and this reference will be imported to the project
  • Whenever one is adding an hbm.xml file, for this sort of setup, it is very important that this file is set as Embedded Resource. This is imperative because by doing so, these resources can easily be found by the NHibernate framework. To do so, follow the steps below:
    1. In the Solution Explorer, right-click with the mouse on the file and click on Properties
    2. In the Build Action section, select Embedded Resource.
    3. Save this configuration by pressing ctrl-s.

Basic Classes for Handling NHibernate

Now that the project is setup, the classes for using NHibernate must be defined. They are NHibernateHelper and SessionHelper, both created in the NHibernate directory of the downloadable project.

Below is shown the 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();
        }
    }
} 

This class configures the NHibernate by accessing its data from the Web.Config file. This is done in the property SessionFactory. Basically, using the Configuration.Configure() parameterless method, the framework fetch the configuration data from the Web.Config file. Also observe that the session is stored in a static ISessionFactory object called _sessionFactory. Whenever the SessionFactory property is called again, if there is already a _sessionFactory object, no new instance is created, thus the already existent one is used. Note here that the Singleton Design Pattern is implemented. This is done in this fashion because building the ISessionFactory object is expensive, making the usage of a Singleton elegant.

The other methods in the NHibernateHelper class simply manipulate the session. Next, see the SessionHelper class.

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();
        }
    }
} 

This class serves only as a wrapper for the NHibernateHelper. One may even choose not to implement it and use directly the NHibernateHelper itself, however one may find this wrapper rather useful.

Configuring NHibernate Database Settings and Log4Net in Web.Config

After the basic things are setup, one needs to configure NHibernate database settings and optionally Log4net as well. Since the Web.Config file is fairly small, it will be fully displayed below:

<?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> 

Within the configSections tags, one can see the declaration of NHibernate and Log4net sections. Also, observe that within the connectionStrings tags there is the Connection String called DatabaseConnectionString which is used for NHibernate database configuration.

If one takes a look at the log4net tags, one will see the Log4net configuration settings. The logger named WebAppBasicNHibernateLogger is used to log the application's events and the NHibernate.SQL to log the NHibernate`s ones. Observe that the NHibernate.SQL has its debug level set as DEBUG, which enables all queries that are run to logged. Finally, for that matter, note that both WebAppBasicNHibernateLogger and NHibernate.SQL use as their logging mechanism the LogFileAppender, which basically logs data in a disk file, which the setup is in its configuration.

The NHibernate settings can be found between the hibernate-configuration tags. See that the DatabaseConnectionString is used, the Microsoft SQL Server is the selected dialect, the Assembly name matches the application's, the database will be updated automatically (because of the tag hbm2ddl.auto set to update) and finally the SQL queries are configured to be displayed (because of the tag show_sql set to true). This is the core of the NHibernate configuration. Here one can change the Connection String being used, the SQL language, the Assembly of data models, how the database is updated, and so on. So, pay special attention to these settings and learn how to change them correctly.

Finally, it is important to emphasize that in order to run the downloadable application, a database with the settings declared in this Connection String DatabaseConnectionString must be created. Note that you can change these settings as desired. Also, the downloadable application was tested using SQL Server 2008 Express Edition.

Setting Up NHibernate Session in the Global.asax

Here, may be the must crucial part of the NHibernate setup. If one chooses to use lazy loading for the Entities, the Session opening and closing have to be used accordingly here.

In order to allow lazy loading, NHibernate has to be open its Session in the beginning of the request, and closed in the end of it. Therefore, the Global.asax is the right place to do so, because it catches all events when the request is open and when it is closed. Below is shown the code which does what was explained:

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();
}

Note how it is straightforward to setup the Session of NHibernate in the Global.asax file, for lazy loading. Simply capture the request start event, open the session, capture the request end event and finally close the Session. Observe that a new object is created every time the Session is opened or closed, however this does not matter for performance matters because the ISessionFactory itself is treated as a Singleton in the NHibernateHelper class.

One last observation is about the Log4net, which is initialized in the event where the application is started, as shown below:

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

One could finish reading this article here, because everything needed to setup NHibernate was explained. Next will be shown how to create NHibernate Entities, Data Access Objects (DAOs), and a few more interesting topics to be discussed.

Create Entities Mapped from the Database

The first thing to do in order to start using NHibernate is to create Entities which will map database tables into Value Objects. To do so, one needs to create a Class representing the Value Object and its mapping into an XML file, usually named as: FILE_NAME.hbm.xml. Here will be repeated something which were already stated in this article: the hbm.xml files must be configured as Embedded Resources, for the application to work as described throughout this article.

The downloadable application comes with a small mechanism to reuse code when creating Entities and Data Access Objects (DAOs). This mechanism, as will be demonstrated, is quite simple, yet will save up a lot of coding. Below is its class diagram:

UML diagram of VO/DAO NHibernate mechanism

Basically, two classes are used for the mechanism: the BaseVo and BaseDao. All Entities are to inherit from BaseVo and all Data Access Objects (DAOs) are to inherit from BaseDao. BaseVo holds the Id property, which is used as an Identifier for all entities. Its type is a Generic one, thus it is defined when the BaseVo is subclassed. Having this Id in a base class saves the need for every Entity to define its Identifier. Moreover, the BaseVo and its Identifier are used in the BaseDao, which implements methods that are useful for every Data Access Object of NHibernate. Having all DAOs inheriting from the base class, make all these methods reusable.

Since this article only intends to depict basic NHibernate setup, here will be created only one Entity with its mapping, providing only a few examples of database interaction: the Person and PersonDao, as one can see in the class diagram.

Now, have a look at the BaseVo class:

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; }
    }
} 

Note how straightforward the class is. Also observe the use of Generics for the Identifier. Next, have a look at the BaseDao class:

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&acute;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();
        }
    }
}  

Note how this class uses Generics for gathering the Entity Identifier and the Entity itself. See as well how the Entity Generic must inherit from BaseVo, making the mechanism more robust. Moreover, many useful methods are implementing using the NHibernate API, along with the Generics Entity and Identifier. Whenever a class inherits from the BaseDao, automatically these Generics values will be filled in and the methods will be useful for this very class.

Finally, look below the Person and 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();
            }
        }
    }
} 

Note how much code is saved, since PersonDao has only one implemented method but have several automatically inherited.

The Person.hbm.xml also is important here, and it is shown below:

<?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> 

Note the mapping of table columns into object properties. Also observe the table definition. One important detail to be seen is the usage of the application's namespace.

Having the Entity and its Data Access Object setup, one is ready to do some database operations. This is discussed next.

Examples of Database Interactions

The downloadable application has a few examples of the NHibernate usage. This session will demonstrate them. Below is shown the full code of Global.asax. Note that in the Application_Start event, a series of NHibernate database operations are performed. Three entities are created and one is deleted. Moreover, observe the use of the Default Microsoft .NET transaction. This is allowed and there is no difference between using this transaction and the one provided by NHibernate. To be fair, NHibernate transaction has one huge disadvantage: it cannot be nested within another NHibernate transaction. This can complicate things because one has to be careful whenever a method is calling another, to see if they all make the use of only one NHibernate transaction.

Another important statement: the event Application_Start is executed only when the application is started. For it to be executed again, the Internet Information Services (IIS) has to be restarted.

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)
        {
 
        }
    }
} 

Another example can be observed in the Default.aspx.cs. Here, more NHibernate database operations are performed. Note that the NHibernate transaction is used. Remember, there cannot be nested exceptions for this sort of transaction.

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();
        }
    }
} 

This finalizes the code explanation. Please, do not forget to create the database in order to run this application. The configurations are set in the Web.Config file, as explained earlier.

Running the Code

The Project compilation and execution is straightforward:

  1. Open the Project using Microsoft Visual Web Developer 2010 or later. Of course, one can use Visual Studio.
  2. Compile the project. Note that for the first, all necessary libraries will be automatically downloaded via NuGet.
  3. Run the Project.

When the project is run, the database tables will be created and the operations in the Global.asax will be executed only when the software is started. They will be executed again only if one restarts Internet Information Services (IIS), as mentioned before. If the application is successfully executed, a screen like the one displayed below will appear:

If you press ªExecute NHibernate Operationsª a few NHibernate database operations will be executed. They were already discussed in the previous session. One can see the results persisted in the database.

Discussion

Although the article is extensive, note that setting up NHibernate is not complicated. Basically, one needs to import the required libraries, setup basic Session classes, configure the database and start implementing the Value Object and Data Access Object classes.

NHibernate is a powerful framework, it is widely used among Microsoft .NET developers and even more utilized among Java users, of course making use of the Hibernate framework.

NHibernate is so famous because it saves up a lot of time in coding. Basically because it makes the conversion from database data to software object automatically, and vice-versa. It also allows developers to build complex queries in code, which eases immensely the software development and maintenance.

As a negative point, NHibernate has quite a steep learning curve, making its learning something not so trivial. However, since developers love a good challenge, this framework is worth mastering.

Microsoft released the Entity Framework which with all due respect to Microsoft, is a copy of NHibernate with visual modeling wizards. Even so, the first versions of Entity Framework left much room for improvement, which proves how hard it is to build such a framework, and how mature NHibernate is.

With the QueryOver API, NHibernate is still easier to use than Entity Framework and even to date, it is more reliable to use with other databases than Microsoft SQL Server.

To summarize, NHibernate is a great framework and hopefully will be around for many years.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here