ASP.NET MVC is a common framework for developing web applications. As we all know that M in MVC stands for model, and for a Line of business (LoB application ), the model is often the backbone. For defining a model that persists in a database, ASP.NET MVC supports Entity Framework (now Open Source) out of the box. Other possible options are:
ADO.NET hand coded data layer where you write all the queries explicitly.
- Use commercial O/R mappers like LLBLGen
- Use Open Source O/R mapper like NHibernate.
Today we will see how we can get started using Nhibernate
Getting Started with NHibernate
You can get additional information about the NHibernate from here.
Once you identify various models and relationship in your data model, you can now introduce NHibernate for mapping these models to a persistence store like (SQL Server, Oracle etc).
One of the most important part of using ORM is establishing mapping between Model objects and the Database tables. If we use NHibernate, then this mapping needs to be set explicitly using XML file.
In the following steps, we will be exploring use of NHibernate in ASP.NET MVC 4 application.
Step 1: Open VS 2012 and create MVC 4 application. On the project, right click and select Manage NuGet Packages’. You will see the Manage Nuget Packages screen. In the search TextBox enter ‘NHibernate’ and you will get the following result:
Once you click the ‘Install’, you will get below references in then project:
- NHibernate
- Lesi.Collections
Step 2: Now it is a time to define the Model layer. As I wrote in the beginning that based upon the application requirement, you need to decide upon the Model objects and the relationship between them. So now let’s define an application that is used to maintain employee records (very simple, but you can extend the concept). Let’s add the new class in the Models folder as shown below:
public class EmployeeInfo
{
int _EmpNo;
public virtual int EmpNo
{
get { return _EmpNo; }
set { _EmpNo = value; }
}
string _EmpName;
public virtual string EmpName
{
get { return _EmpName; }
set { _EmpName = value; }
}
int _Salary;
public virtual int Salary
{
get { return _Salary; }
set { _Salary = value; }
}
string _DeptName;
public virtual string DeptName
{
get { return _DeptName; }
set { _DeptName = value; }
}
string _Designation;
public virtual string Designation
{
get { return _Designation; }
set { _Designation = value; }
}
}
The class EmployeeInfo contains properties. These properties will be used for mapping with the Table Columns. These properties are defined as virtual properties because of the lazy association which is used by NHibernate to set proxy entity on association property.
Step 3: Once the Model class for mapping is ready, now let’s think of the database to persist the data. For this simple application, we will use a database called Company in SQL Server. The name of the table is EmployeeInfo which can be created as shown below:
USE [Company]
GO
/****** Object: Table [dbo].[EmployeeInfo] Script Date: 1/17/2013 11:22:12 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[EmployeeInfo](
[EmpNo] [int] IDENTITY(1,1) NOT NULL,
[EmpName] [varchar](50) NOT NULL,
[Salary] [decimal](18, 0) NOT NULL,
[DeptName] [varchar](50) NOT NULL,
[Designation] [varchar](50) NOT NULL,
CONSTRAINT [PK_EmployeeInfo] PRIMARY KEY CLUSTERED
(
[EmpNo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
Step 4: To set the mapping, we need to add an XML file in the project as ‘Embedded Resource’. For this sample, I’ll use two folders under the default Model folder - NHibernate\Configuration and NHibernate\Mappings.
The naming convention for the mapping files are by default <ModelName>.hbm.xml, so in our case it will be ‘EmployeeInfo.hbm.xml’. This file goes into the Mappings folder. This file maps the Model class with the database table columns with the constraints like primary key, data types etc. The file is as shown below:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
assembly="MVC4_Using_NHB"
namespace="MVC4_Using_NHB"
auto-import="true">
<class name="MVC4_Using_NHB.Models.EmployeeInfo,MVC4_Using_NHB">
<id name="EmpNo" access="property" column="EmpNo" type="Int32">
<generator class="native"></generator>
</id>
<property name="EmpName" access="property"
column="EmpName" type="String"></property>
<property name="Salary" access="property"
column="Salary" type="Int32"></property>
<property name="DeptName" access="property"
column="DeptName" type="String"></property>
<property name="Designation" access="property"
column="Designation" type="String"></property>
</class>
</hibernate-mapping>
The above xml file demonstrates the mapping between EmployeeInfo class and its properties with the columns. The mapping table is defined by the NHibernate APIs while establishing connection to database.
Note: One important thing is that by default no intellisense is available so to achieve this add nhibernate-configuration.xsd and nhibernate-mapping.xsd in below path
C:\Program Files (x86)\Microsoft Visual Studio 11.0\Xml\Schemas
Step 5: Once the mapping is defined, now let’s define the NHibernate configuration for the application. This provides information about the database provider, connection string and the mapping file used for the connectivity. So in the project, add a new XML file in the Models\Configuration folder created above; the name of the file will be ‘hibernate.cfg.xml’. Add the following configuration in it:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Data Source=.;Initial Catalog=Company;Integrated Security=SSPI</property>
<property name="show_sql">false</property>
</session-factory>
</hibernate-configuration>
Step 6: Now it’s time to add some code to do CRUD operations against the database table using the mapping model. NHibernate provides various classes and interfaces for performing operations, some of them are used in this implementation and they are as below:
ISession: This is a main runtime interface between NHibernate and .NET and is used to manipulate entities.
ISessionFactory: A Session is created by this interface. The method ‘OpenSession()’ is provided to create session. One session factory is required per database. The implementation is thread safe and can live till the life time of the application.
As you can see in the code below, we have provided the absolute path of the configuration file to the configuration object and also provided it with the Directory Information where all the mapping files will be kept (in the OpenSession method).
IQuery: This is an object representation of NHibernate query. This is created using ‘CreateQuery()’ method of the ISession. This is the method where the table name is passed and based upon which column the mapping can take place.
ITransaction: Used to manage transactions. This is required during DML operations.
Add a new class in the Models folder and add the following code in it:
/// <summary>
/// class to perform the CRUD operations
/// </summary>
public class EmployeeInfoDAL
{
//Define the session factory, this is per database
ISessionFactory sessionFactory;
/// <summary>
/// Method to create session and manage entities
/// </summary>
/// <returns></returns>
ISession OpenSession()
{
if (sessionFactory == null)
{
var cgf = new Configuration();
var data = cgf.Configure(
HttpContext.Current.Server.MapPath(
@"Models\NHibernate\Configuration\hibernate.cfg.xml"));
cgf.AddDirectory(new System.IO.DirectoryInfo(
HttpContext.Current.Server.MapPath(@"Models\NHibernate\Mappings")));
sessionFactory = data.BuildSessionFactory();
}
return sessionFactory.OpenSession();
}
public IList<EmployeeInfo> GetEmployees()
{
IList<EmployeeInfo> Employees;
using (ISession session = OpenSession())
{
//NHibernate query
IQuery query = session.CreateQuery("from EmployeeInfo");
Employees = query.List<EmployeeInfo>();
}
return Employees;
}
public EmployeeInfo GetEmployeeById(int Id)
{
EmployeeInfo Emp = new EmployeeInfo();
using (ISession session = OpenSession())
{
Emp = session.Get<EmployeeInfo>(Id);
}
return Emp;
}
public int CreateEmployee(EmployeeInfo Emp)
{
int EmpNo = 0;
using (ISession session = OpenSession())
{
//Perform transaction
using (ITransaction tran = session.BeginTransaction())
{
session.Save(Emp);
tran.Commit();
}
}
return EmpNo;
}
public void UpdateEmployee(EmployeeInfo Emp)
{
using (ISession session = OpenSession())
{
using (ITransaction tran = session.BeginTransaction())
{
session.Update(Emp);
tran.Commit();
}
}
}
public void DeleteEmployee(EmployeeInfo Emp)
{
using (ISession session = OpenSession())
{
using (ITransaction tran = session.BeginTransaction())
{
session.Delete(Emp);
tran.Commit();
}
}
}
}
Build the project and make sure that it is error free.
Step 7: Add a new Controller in the Controllers folder, name it as ‘EmployeeInfoController’. Add the following action methods in the controller class:
using MVC4_Using_NHB.Models;
using System.Web.Mvc;
namespace MVC4_Using_NHB.Controllers
{
public class EmployeeInfoController : Controller
{
EmployeeInfoDAL objDs;
public EmployeeInfoController()
{
objDs = new EmployeeInfoDAL();
}
//
// GET: /EmployeeInfo/
public ActionResult Index()
{
var Employees = objDs.GetEmployees();
return View(Employees);
}
//
// GET: /EmployeeInfo/Details/5
public ActionResult Details(int id)
{
return View();
}
//
// GET: /EmployeeInfo/Create
public ActionResult Create()
{
var Emp = new EmployeeInfo();
return View(Emp);
}
//
// POST: /EmployeeInfo/Create
[HttpPost]
public ActionResult Create(EmployeeInfo Emp)
{
try
{
objDs.CreateEmployee(Emp);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
//
// GET: /EmployeeInfo/Edit/5
public ActionResult Edit(int id)
{
var Emp = objDs.GetEmployeeById(id);
return View(Emp);
}
//
// POST: /EmployeeInfo/Edit/5
[HttpPost]
public ActionResult Edit(int id, EmployeeInfo Emp)
{
try
{
objDs.UpdateEmployee(Emp);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
//
// GET: /EmployeeInfo/Delete/5
public ActionResult Delete(int id)
{
var Emp = objDs.GetEmployeeById(id);
return View(Emp);
}
//
// POST: /EmployeeInfo/Delete/5
[HttpPost]
public ActionResult Delete(int id,FormCollection collection)
{
try
{
var Emp = objDs.GetEmployeeById(id);
objDs.DeleteEmployee(Emp);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
Each action method makes a call to the method defined in the EmployeeInfoDAL class. That’s it. Now add views for each action method and test them.
Conclusion
We saw how easy it is to make use of NHibernate in MVC application for building Line of Business (LOB) applications.