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.
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
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.The Sample code for this application is at https://github.com/devcurry/introducing-nhibernate-mvc
Thanks for taking the time to write this up.
ReplyDeleteNice blog for freshers.
ReplyDeletePlease help me. I am getting this error while performing DML operation:
An exception occurred during configuration of persistence layer.
Thanks in advance.
Nice article!. One Important typo is that you have mentioned "Lesi.Collections" instead of Iesi.Collections i.e. you have used "L" instead of "I" since it contains some special implementations of ISet.
ReplyDelete@Rohit
ReplyDeleteI had the same problem but substuting this:
System.Web.Hosting.HostingEnvironment.MapPath("~/Models/NHibernate/Configuration/hibernate.cfg.xml")
for this:
HttpContext.Current.Server.MapPath( @"Models\NHibernate\Configuration\hibernate.cfg.xml"));
Seemed to help
The web.config in your solution is still using the Entity Framework. You never covered removing that reference. How do you know that you're actually using NHibernate to get the data?
ReplyDeletehow to create view pls, send instruction to my mail yantarb@rambler.ru
ReplyDeletety!
Hi. I've created a MVC Internet Project from one of VS 2012 templates. I've added NHibernate as you explained and also I've changed this HttpContext.Current.Server.MapPath( @"Models\NHibernate\Configuration\hibernate.cfg.xml"));
ReplyDeletefor this
HttpContext.Current.Server.MapPath( @"~\Models\NHibernate\Configuration\hibernate.cfg.xml"));
as one of the above comment said.
But it give me an exception at this line
sessionFactory = data.BuildSessionFactory ();
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections.
I've google it but I'm using a default database created by VS for this template and I don't have acces to it's properties to make thouse modifications sugested by the people who had the same problem.
Any idea how to fix this. Thanks.
PS: Nice job!
I've fix it. The problem was in my cfg file. In the connection.string I've copied the connection string provided by VS in server explorer database properties connection. Hope this helps.
ReplyDeleteImportant thing!!! If you will user many-to-one or one-to-many relations mapping use fully qualified names for your entities. I've spend hours for not doing so :). Ex: instead of just class="EmployeeInfo" use class="yourProjectName.Models.EmployeeInfo".
ReplyDeleteHope this helps!
I am new for MVC so please help me for View code fot this demo..
ReplyDelete