Introduction
A few days ago I wrote an article on “NHibernate in Details” that can be found in the C# Corner website with NHibernate in Details: Part 1 covering the use of popular ORMs such as Hibernate. Within the .Net perspective, it is known as “NHibernate”. This article is Part 2 in continuation of that and uses the same sample Employee Projects created in Part 1. So Let's start to understand NHibernate from the basics.
NHibernate
NHibernate is an ORM framework for mapping a domain model class to a traditional relational database or a kind of Object Relational Mapper that is a port of the popular Java ORM Hibernate. It serves as a persistence layer coupled with a database layer and Plain Old CLR Objects (POCOs). NHibernate relies on .NET reflection and a supportive library from NHibernate.dll.
Definition according to Wikipedia
“NHibernate is an object-relational mapping (ORM) solution for the Microsoft .NET platform. It provides a framework for mapping an object-oriented domain model to a traditional relational database. Its purpose is to relieve the developer from a significant portion of relational data persistence-related programming tasks. NHibernate is free as open source software that is distributed under the GNU Lesser General Public License. NHibernate is a port of Hibernate. ”.
The Saga of Persistence
The concept of Software Development revolves around the need for the creation of data and the persisting or storage of data, retrieving data from the pool or database in a fast and organized manner. The characteristic of an efficient software development practice is to choose a good software development methodology and design pattern to store data in simple binary or text files on a database or disks. We currently have a variety of formats to save data, such as CSV, XML, and JSON formats. Thus managing data persistence is currently a hot topic.
In ASP.Net to save and retrieve data we can use a dataset or data reader but for all these we need to hardcode the SQL query to interact with the database. NHibernate comes to the rescue to eliminate the necessity of writing all those queries many times and interacting with the database.
But the software development concepts are mainly based on the database concepts of persisting data and searching or retrieving of data using a SQL query. However, the database management system creates a problem if we start thinking in the context of an object-oriented approach or domain model.
An application with a domain model having inheritance, collection classes, and composition does not fit with a relational or tabular representation of database. Thus using a .NET application we can define classes having OOP concepts rather than simply using Data Tables. This is in general known as an impedance mismatch or paradigm mismatch (or object/relational structural mismatch) as described in terms of.
- The problem of granularity.
- The problem of inheritance and polymorphism.
- The problem of association.
- The problem of Identity and so on.
Advantages of NHibernate
- NHibernate is an ORM framework and Object Relational Mapping tool.
- It is a framework to map the data of an Object Domain with the data of a Relational Domain.
- It is used to overcome the problem encountered by a developer to persist data in databases and the need to fetch persistent data from databases.
Why Choose NHibernate?
- In general, the ASP.NET framework uses ADO.NET to deal with the database interaction.
- The problem with the manual creation of a Data Access Layer (DAL) for interacting with a database system is that a developer needs to do all the database-related tasks such as opening the connection, creating a query, executing the query, closing the connection, and so on. In other words, a developer must be an expert in both, the Object Domain as well as the Relational Domain.
- The NHibernate comes to the rescue to handle most of the work of persisting objects in the database, thus providing a solution for the problem of impedance mismatch.
- XML files play an important role in the configuration and mapping of information between objects and relational databases.
NHibernate Architecture in General
The NHibernate architecture provides multiple layers in its ORM framework as shown below.
- On the top, it consists of an ASP.NET or Windows Application layer.
- ASP.NET uses persistence objects (POCOs) to interact with SessionFactory, Session, and Transaction interfaces.
- Session Objects interact with the ADO.NET API or ODBC / OLEDB to do a query for storing and retrieving data or we can use a standard ADO.NET command for it.
- NHibernate has support for interacting with a variety of different databases to store data or persist objects.
Persistent of objects without NHibernate
Procedure
- The ASP.NET application creates Business Objects.
- The Business Objects interact with the DAL to create and formulate a SQL Query.
- The DAL interacts with the underlying database using ADO.NET.
- All interactions (CRUD operations) are saved into the database for future interaction.
Persistent of objects with NHibernate
Procedure
- Creates Business Objects An ASP.NET application creates Business Objects in the form of POCO classes to be persisted. A POCO / persistent class must have the following characteristics.
- It has an ID or unique identifier to be used by NHibernate to uniquely identify objects and generate primary keys and so on.
- It must provide getter and setter methods for all its properties.
- A property must be marked virtual to help NHibernate to create a proxy.
- Creation of Configuration Objects Business Objects (POCOs) interact with the ORM Framework.
- The ORM Framework gets information about the database from the XML files such as web.config or hibernate.cfg.xml.
- The configuration files provide information about the database connection, dialects, Show_Sql query, hbm2sql and so on.
- Creation of Mapping Information from POCO Objects and Tables A mapping file for mapping Objects and their relations with the database needs to be created.
- It specifies information about what property of objects are mapped to which tables and columns and how the data of the objects are to be persisted.
- The Mapping file must have a name such as Object name + prefix with “xxxx.hbm.xml”, in other words Employee.hbm.xml.
- Creation of Session Factory The NHibernate Framework creates the following object to create a query by itself depending on what CRUD operation is required and saves the objects into the database.
- A configuration object is created.
- A Session Factory is obtained from configuration objects.
- Gets a Session object from the Session Factory.
- Creates Transaction objects.
- Objects are passed to the Session for persisting in the database.
- Commit the Transaction.
This is as shown below.
Note. For Part 1, refer to NHibernate in Details.
Rules/Constraints for developing NHibernate projects
For Mapping with Plain Old CLR Objects (POCOs).
For NHibernate Mapping with a Database.
Converting SQL database types to .NET types
It must be useful to know what types of data from an SQL database maps with .NET types. For example: “int of SQL Server became an Integer, whereas a varchar became a String”.
This can be understood from the following table.
Overview of NHibernate objects and interfaces
The various Objects and Classes used in NHibernate are:
- Configuration Objects
- SessionFactory Interface
- Session Interface
- Transaction Interface
Let's discuss them one by one
Web.Config: Configuration Objects
NHibernate specifies configuration information on the web. config file and uses configuration objects in an aspx page to retrieve configuration information in object form. In web. config the configuration information needs to be specified that helps NHibernate to connect with the specified database and map the resource files assembly, in other words, .hbm.xml file.
Note. For the code please refer to the article's Part 1 NHibernate in Details.
The various sections are specified on the web. config file are as shown below.
<configuration>
<configSections>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate"></section>
</configSections>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="hbm2ddl.auto">update</property>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="dialect">
NHibernate.Dialect.MsSql2008Dialect
</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
Data Source=(local);Integrated Security=True; initial catalog=Test
</property>
<property name="show_sql">
true
</property>
<mapping assembly="EMPNHibernate" />
</session-factory>
</hibernate-configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
</configuration>
Abstract factory pattern SessionFactory Interface
The NHibernate framework uses the abstract factory pattern for creating sessions and using them to persist the objects into the database.
It is a factory class that is used in an aspx page to create session objects. The SesionFactory Objects can be created or built from the configuration objects (.cfg.xml) as shown below.
public static ISession OpenSession()
{
var configuration = new Configuration();
configuration.Configure();
ISessionFactory sessionFactory = configuration.BuildSessionFactory();
return sessionFactory.OpenSession();
}
Why Sessions From ASP.NET Do Not Work Well?
Since ASP.NET sessions are stateless in nature and NHibernate requires the use of a single session that can be spread across several pages or requests, this stateless nature of a normal ASP.NET session makes it difficult to maintain and perform transactions in applications.
Singleton pattern: NHibernate uses the Singleton pattern to store the session in the user's context and do transactions. The Singleton pattern can be simply created by creating a sealed class having all member methods and variables declared static. This class can have a property called Instance. This class can also have a non-static constructor that has the implementation details.
In simple terms, we can create a simple class with NHibertnateSession with a static method in it as in the following.
public class NHibertnateSession
{
public static ISession OpenSession()
{
var configuration = new Configuration();
configuration.Configure();
ISessionFactory sessionFactory = configuration.BuildSessionFactory();
return sessionFactory.OpenSession();
}
}
This session can also used to manage the second-level caching of persistent objects, in other words from EHChache or OSCached, Memcached, and so on.
Session Interfaces
The Session objects can be created from the SessionFactory created as in the preceding.
So when we want to create a session, we just ask the session factory to open a session using.
ISession session = sessionFactory.OpenSession();
or
ISession session = NHibertnateSession.OpenSession();
Where NHibernateSession is our Session Factory.
For Example. To OpenSession from Session Factory.
ISession session = NHibertnateSession.OpenSession();
Employee emp = new Employee();
emp.FirstName = txtName.Text;
emp.LastName = txtLastName.Text;
emp.Designation = txtDes.Text;
session.Save(emp);
This interface provides methods for persisting objects, creating transactions, performing query operations, and so on with NHibernate. NHibernate handles all the interaction with the databases, such as for opening, pooling, and closing connections and so on.
Transaction Interfaces
The Transaction interface is used to encapsulate our CRUD statements in "transaction" objects that must begin and be committed at the end.
First to start the transaction from a session using begins.
session.BeginTransaction();
Transaction tx = session.BeginTransaction();
For Example. To use Transaction Interfaces.
public void loadData()
{
using (ISession session = NHibertnateSession.OpenSession())
{
using (var tx = session.BeginTransaction())
{
/*** Using Query ***/
var employees = session.Query<Employee>().ToList();
foreach (var emp in employees)
{
Response.Write(emp.FirstName + emp.LastName);
}
tx.Commit();
}
}
}
- The Transaction API is used by NHibernate to perform a transaction getting the current session of an ISession interface for this HTTP request from SessionFactory.
- The ISession is closed after the transaction completes, either in the Application_EndRequest event handler in our application class or in an HttpModule before the HTTP response is sent.
- This is also known as lazy initialization since the ISession is still open when the view is rendered, so NHibernate can load uninitialized objects before performing any transactions.
Hibernate Query Language (HQL) and Criteria API
NHibernate uses the Hibernate Query Language (HQL) to create a query with the databases. NHibernate also uses an object-oriented query using a criteria API that can be used to formulate type-safe queries.
For Example
var employees = session.CreateCriteria<Employee>("From Employee").List<Employee>();
ADO.NET Query with NHibernate
NHibernate can also be used to do normal ADO.NET queries as done earlier.
protected void Deleteobjects()
{
ISession session = NHibertnateSession.OpenSession();
// Clear the previous entries
SqlConnection connection = session.Connection as SqlConnection;
SqlCommand command = new SqlCommand("Delete from Employee", connection);
command.ExecuteNonQuery();
}
This is the end of Part 2, here I tried to provide basic information about NHibernate and its usefulness in the .Net world of Object Persistence. In Part 3 we will jump into the concepts of Hibernate application development. Please post comments.