Hand written data access code in something like doing same thing for many times for every project, it is error prone and time consuming. Today there are many frameworks are out there for doing this. One approach is object relational mapper (ORM). The advantage of ORM is application developer can work with objects in object oriented manner, whereas ORM frameworks are filling the gap between database relational structure and object oriented structure. There are many ORM frameworks out there like LINQ to SQL, Entity Framework and NHibernate etc.
Today I am going to tell you about NHibernate. Hibernate is very popular in Java community and NHibernate project is for .NET framework. It is open source and very powerful. The most suitable thing for NHibernate is it supports POCO. POCO means Plain Old CLR Object.
So what NHibernate does? It is a persisting layer for .NET applications. We have the POCO, the database and the mapping file. Then it will store data from objects to database and retrieve data from database to objects. It also takes care of data caching, database session, transaction, relation. You can also implement relations in mapping file. There are some tools which generate mapping file and database for us. It also supports code first development. That means developer can concentrate on business logic and NHibernate takes care of how your business data will persists in databases.
Now I am going to develop a very simple demo application using NHibernate. This is my first NHibernate application. Also one more thing I want to share with you is that I am using ASP.NET MVC for this demo application. I will write more about ASP.NET MVC in my latter posts.
Open VWD 2010 Express Edition. Create a new ASP.NET MVC application. Add Northwind database file in App_Data folder. Create two classes in Models folder. One is Customer.cs and another is CustomerDb.cs. Add a new folder in your solution and give a name as Mappings. Create a new xml file called Customer.hbm.xml inside that folder. This is my setup. The plan is I am going to retrieve all customer data from database to customer object collection and display it in the browser. For that I have created my customer class (POCO), customer data access layer and a mapping xml file to map customer object data with database customers table.
Customer.cs
namespace MvcApplication2.Models { public class Customer { public virtual string CustomerId { get; set; } public virtual string CompanyName { get; set; } public virtual string ContactName { get; set; } public virtual string ContactTitle { get; set; } public virtual string Address { get; set; } public virtual string City { get; set; } public virtual string Region { get; set; } public virtual string PostalCode { get; set; } public virtual string Country { get; set; } public virtual string Phone { get; set; } public virtual string Fax { get; set; } } }
CustomerDb.cs
using System.Collections.Generic; using NHibernate; using NHibernate.Cfg; using SystemConfig = System.Configuration; namespace MvcApplication2.Models { public class CustomerDb { public ISession Session { get; set; } public CustomerDb() { string connectionString = SystemConfig::ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString; Configuration theConfiguration = GetConfiguration(connectionString); CreateSession(theConfiguration); } public CustomerDb(ISession session) { Session = session; } public IList<Customer> GetAll() { ICriteria theCriteria = Session.CreateCriteria<Customer>(); IList<Customer> customers = theCriteria.List<Customer>(); return customers; } private Configuration GetConfiguration(string connectionString) { Configuration theConfiguration = new Configuration(); theConfiguration.Properties.Add(NHibernate.Cfg.Environment.ConnectionProvider, typeof(NHibernate.Connection.DriverConnectionProvider).AssemblyQualifiedName); theConfiguration.Properties.Add(NHibernate.Cfg.Environment.Dialect, typeof(NHibernate.Dialect.MsSql2008Dialect).AssemblyQualifiedName); theConfiguration.Properties.Add(NHibernate.Cfg.Environment.ConnectionDriver, typeof(NHibernate.Driver.SqlClientDriver).AssemblyQualifiedName); theConfiguration.Properties.Add(NHibernate.Cfg.Environment.ConnectionString, connectionString); theConfiguration.AddAssembly(typeof(Customer).Assembly); return theConfiguration; } private void CreateSession(Configuration theConfiguration) { ISessionFactory sessionFactory = theConfiguration.BuildSessionFactory(); Session = sessionFactory.OpenSession(); } } }
Customer.hbm.xml
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> <class name="MvcApplication2.Models.Customer, MvcApplication2" table="Customers"> <id name="CustomerId" type="string"> <column name="CustomerID" /> </id> <property name="CompanyName" type="string" /> <property name="ContactName" type="string" /> <property name="ContactTitle" type="string" /> <property name="Address" type="string" /> <property name="City" type="string" /> <property name="Region" type="string" /> <property name="PostalCode" type="string" /> <property name="Country" type="string" /> <property name="Phone" type="string" /> <property name="Fax" type="string" /> </class> </hibernate-mapping>
To access the data there is a use of ISession object. This object is created using a factory pattern.
Configuration theConfiguration = new Configuration(); theConfiguration.Properties.Add(NHibernate.Cfg.Environment.ConnectionProvider, typeof(NHibernate.Connection.DriverConnectionProvider).AssemblyQualifiedName); theConfiguration.Properties.Add(NHibernate.Cfg.Environment.Dialect, typeof(NHibernate.Dialect.MsSql2008Dialect).AssemblyQualifiedName); theConfiguration.Properties.Add(NHibernate.Cfg.Environment.ConnectionDriver, typeof(NHibernate.Driver.SqlClientDriver).AssemblyQualifiedName); theConfiguration.Properties.Add(NHibernate.Cfg.Environment.ConnectionString, connectionString); theConfiguration.AddAssembly(typeof(Customer).Assembly); ISessionFactory sessionFactory = theConfiguration.BuildSessionFactory(); Session = sessionFactory.OpenSession();
When configuration object is created then it read the mapping file. For that make sure the mapping file is compiled in the assembly as an embedded recource to find it by NHibernate. Now using that ISession object we can retreve all customer records from database.
ICriteria theCriteria = Session.CreateCriteria<Customer>(); IList<Customer> customers = theCriteria.List<Customer>();
Now add a new controller name CustomerController.cs. Inside the controller add a new Index() action method.
using System.Collections.Generic; using System.Web.Mvc; using MvcApplication2.Models; namespace MvcApplication2.Controllers { public class CustomerController : Controller { public ActionResult Index() { CustomerDb dal = new CustomerDb(); IList<Customer> customers = dal.GetAll(); return View(customers); } } }
Now right click on the Index() method and add a new view name Index. Select a strongly type view and select our customer class (POCO) as a strongly type for the view. Now instruct visual studio to create default template for List all the customer data in the Index view. Also select the use master page option for the view.
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<MvcApplication2.Models.Customer>>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Index </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Index</h2> <table> <tr> <th></th> <th>CustomerId</th> <th>CompanyName</th> <th>ContactName</th> <th>ContactTitle</th> <th>Address</th> <th>City</th> <th>Region</th> <th>PostalCode</th> <th>Country</th> <th>Phone</th> <th>Fax</th> </tr> <% foreach (var item in Model) { %> <tr> <td> <%: Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) %> | <%: Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ })%> | <%: Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })%> </td> <td><%: item.CustomerId %></td> <td><%: item.CompanyName %></td> <td><%: item.ContactName %></td> <td><%: item.ContactTitle %></td> <td><%: item.Address %></td> <td><%: item.City %></td> <td><%: item.Region %></td> <td><%: item.PostalCode %></td> <td><%: item.Country %></td> <td><%: item.Phone %></td> <td><%: item.Fax %></td> </tr> <% } %> </table> <p><%: Html.ActionLink("Create New", "Create") %></p> </asp:Content>
Go to Site.Master inside Views/Shared folder and open it. Add a new link in the main menu for customer.
<ul id="menu"> <li><%: Html.ActionLink("Home", "Index", "Home")%></li> <li><%: Html.ActionLink("About", "About", "Home")%></li> <li><%: Html.ActionLink("Customer", "Index", "Customer")%></li> </ul>
Now run the application and click on the customer link in the menu. It will call the index() method of the customer controller. This is done by ASP.NET routing. ASP.NET MVC is having heavy use of ASP.NET routing. The controller then retrieves the customer data and stores it inside a customer collection and passes it to view. As a result you can see all the customer records in your browser.
Please go for more reading about the inner workings of NHibernate.