In this article we’ll show you how to create a NHibernate-based application with DHTMLX Scheduler .NET web control in 7 simple steps. 

You'll learn how to create an event calendar, connect it to the database created in SQL Server Management Studio and customize NHibernate for .NET appropriately. 

 

You can get a demo sample created in Visual Studio 2012 right now and proceed with the tutorial:

Step 1. Creation of a New App

Create a new MVC3 Razor project in Visual Studio 2010/2012 and name it ‘DHXSchedulerNHibernate’.

 

Step 2. Installation via NuGet

For this app you have to install two packages via NuGet, namely DHTMLX.Scheduler.MVC3.Sample and NHibernate. 

 

 

Step 3. Updating Default Route

The selected MVC3 sample installs views, a model 'SchedulerModel.cs' and a controller 'CalendarController.cs'. Open Global.asax and change the default controller from Home to Calendar:

routes.MapRoute(

   "Default", // Route name

   "{controller}/{action}/{id}", // URL with parameters

    new { controller = "Calendar", action = "Index", id = UrlParameter.Optional } // Parameter defaults

Once you’ve done it, run the application. You'll get a scheduler demo with ready events:

 

Step 4.  Creation of a Database

Now create a new database in SQL Server Management System. Right-click on the created database to add a new query with the following code:

CREATE TABLE [dbo].[Events] (
   [id] INT IDENTITY(1,1)NOT NULL,
   [text] NVARCHAR (250)NULL,
   [start_date] DATETIME NULL,
   [end_date]  DATETIME NULL,
   PRIMARY KEY CLUSTERED ([id] ASC)
);

Execute the query. 

We use the easiest table structure with only 4 compulsory columns in our sample. That’s why we can use CalendarEvent as a mapping class. It comes with Scheduler .NET sample. Any extra columns would require corresponding properties to be added manually to the class, or urge the creation of a new class.

As far as NHibernate requires all mapped properties to be marked are virtual, update Models/SchedulerModel.cs as follows:

using System;

namespace DHXSchedulerNHibernate.Models
{
   public class CalendarEvent
   {
       public virtual int id { get; set; }
       public virtual string text { get; set; }
       public virtual DateTime start_date { get; set; }
       public virtual DateTime end_date { get; set; }
   }
}

 

Step. 5 NHibernate Customization

This part describes the principle of NHibernate work with the database. We'll have to open a database session, create and execute a transaction, and dispose the session.

NHibernate sessions are created with SessionFactory. As far as the initialization of SessionFactory is relatively costly, it’s important to ensure that initialization happens only once per application.

We’ll create a simple Singleton class that will create a SessionFactory in a static initializer (that is guaranteed to run only once per application domain) and will have a static accessor for the session instance.

We have to create a new folder App_Code and add a new class SessionFactory.cs with the following code:

using NHibernate.Cfg;
using NHibernate;

using System.Reflection;

namespace DHXSchedulerNHibernate
{
   public static class SessionFactory
   {
       private static ISessionFactory _Factory;

       static SessionFactory()
       {
           var configuration = new Configuration();
           configuration.Configure(
               Assembly.GetExecutingAssembly(),
               "DHXSchedulerNHibernate.Mappings.hibernate.cfg.xml"
           );

           _Factory = configuration.BuildSessionFactory();
       }
       public static ISession OpenSession()
       {
           return _Factory.OpenSession();
       }
   }
}

 

Proceed with the tutorial and you'll get the explanation on the applied configuration parameters.

Note: While creating SessionFactory.cs and other .cs files in App_Code folder, make sure they have ‘Compile’ BuildAction in the file properties: 

 

 

Let’s create a helper class ‘EventRepository.cs’ for CRUD operations against our model:

using System;
using System.Collections.Generic;
using System.Linq;
using DHXSchedulerNHibernate.Models;

using NHibernate;
using NHibernate.Criterion;

namespace DHXSchedulerNHibernate
{
   public class EventRepository
   {
       public void Update(CalendarEvent ev)
       {
           using (var session = SessionFactory.OpenSession())
           {
               using (var transaction = session.BeginTransaction())
               {
                   session.Update(ev);
                   transaction.Commit();
               }
           }
       }

       public void Insert(CalendarEvent ev)
       {
           using (var session = SessionFactory.OpenSession())
           {
               using (var transaction = session.BeginTransaction())
               {
                   session.Save(ev);
                   transaction.Commit();
               }
           }
       }

       public void Delete(int id)
       {
           using (var session = SessionFactory.OpenSession())
           {
               using (var transaction = session.BeginTransaction())
               {
                   session.Delete(id);
                   transaction.Commit();
               }
           }
       }
       public CalendarEvent Select(int id)
       {
           using (var session = SessionFactory.OpenSession())
           {
               return session.CreateCriteria<CalendarEvent>()
                   .Add(Restrictions.Eq("id", id))
                       .UniqueResult<CalendarEvent>();
           }
       }

       public IEnumerable<CalendarEvent> Select()
       {
           using (ISession session = SessionFactory.OpenSession())
           {
               return session.CreateCriteria<CalendarEvent>().List<CalendarEvent>();
           }
       }
   }
}

To follow good practices, you can define common interface for CRUD and implement it in EventRepository class, as it is shown below:

 

public interface IRepository<T>{
…
}
public class EventRepository : IRepository<CalendarEvent>{
…
}

The presence of only one model class can complicate the demo, but if you build a more practical app, think of the following solution. 

 

Step 6. Mapping Model to Database

To map the model to the database, we’ll use XML files.  You can also achieve that with tools like Fluent NHibernate or with class attributes.  

You can write configuration data to separate files, place them in the embedded resources or add them to the app.config file.  We’ll use embedded resources.

That’s why had to build up a path to the configuration files in the SessionFactory.cs:             

configuration.Configure(

  Assembly.GetExecutingAssembly(),

  "DHXSchedulerNHibernate.Mappings.hibernate.cfg.xml"

  );

 Note: after you deploy the application, double check there’s no publicly available  xml mapping files.

Create a folder Mappings in the root of your project and add ‘Calendar.Event.hbm.xml’:

<?xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="DHXSchedulerNHibernate.Models" assembly="DHXSchedulerNHibernate">

 <class name="CalendarEvent" table="Events" dynamic-update="true">
   <cache usage="read-write"/>
   <id name="id" column="id" type="int">
     <generator class="native"/>
   </id>
   <property name="text" length="250"/>
   <property name="start_date"/>
   <property name="end_date"/>
 </class> 

</hibernate-mapping>

Note: To let NHibernate get the correct file from the assembly, change the build action in for each map file to the ‘Embedded Resource’.

We are almost done with the project. We need to set up a database connection and customize parameters for NHibernate. Create a new XML configuration file ‘hibernate.cfg.xml’ in the Mappings folder:

<?xml version="1.0" encoding="utf-8" ?>

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="connection.connection_string">Data Source=localhost\SQLEXPRESS;Initial Catalog=model;Integrated Security=True;</property>
    <mapping resource="DHXSchedulerNHibernate.Mappings.CalendarEvent.hbm.xml"   assembly="SchedulerNHibernate" />
  </session-factory>

</hibernate-configuration>

Specify the connection string in the property named ‘connection.connection_string’.

SQL dialect must be specified in the “dialect” parameter. It shouldn’t be necessarily mssql2005, MsSql2008Dialect or MsSql2012Dialect would work as well, however mssql2005 will be enough for most of the things we do.

 

Step 7. Connect NHibernate to Scheduler

We are ready to connect NHibernate to our calendar. Go to Controllers/CalendarController.cs and update Data and Save actions as follows:   

public ContentResult Data()
{
    var data = new SchedulerAjaxData(
    new EventRepository().Select()
    );
    return (ContentResult) data;
}
public ContentResult Save(int ? id, FormCollection actionValues)
{
    var action = new DataAction(actionValues);

    try
    {
        var changedEvent = (CalendarEvent) DHXEventsHelper.Bind(typeof (CalendarEvent), actionValues);

        var repo = new EventRepository();

        switch (action.Type)
        {
        case DataActionTypes.Insert:
            repo.Insert(changedEvent);
            action.TargetId = changedEvent.id; //assign postoperational id
            break;

        case DataActionTypes.Delete:
            repo.Delete(changedEvent.id);
            //do delete
            break;
        default: // "update"                          
            repo.Update(changedEvent);
            break;
        }
    } catch
    {
        action.Type = DataActionTypes.Error;
    }
    return (ContentResult) new AjaxSaveResponse(action);
}

The full code looks like this: 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using DHTMLX.Scheduler;
using DHTMLX.Common;
using DHTMLX.Scheduler.Data;
using DHXSchedulerNHibernate.Models;
namespace DHXSchedulerNHibernate.Controllers
{
    public class CalendarController: Controller
    {
        public ActionResult Index()
        {
            var scheduler = new DHXScheduler(this);
            scheduler.Skin = DHXScheduler.Skins.Terrace;
            scheduler.InitialDate = new DateTime(2012, 09, 03);

            scheduler.Config.multi_day = true;

            scheduler.LoadData = true;
            scheduler.EnableDataprocessor = true;

            return View(scheduler);
        }

        public ContentResult Data()
        {
            var data = new SchedulerAjaxData(
            new EventRepository().Select()
            );
            return (ContentResult) data;
        }

        public ContentResult Save(int ? id, FormCollection actionValues)
        {
            var action = new DataAction(actionValues);

            try
            {
                var changedEvent = (CalendarEvent) DHXEventsHelper.Bind(typeof (CalendarEvent), actionValues);

                var repo = new EventRepository();

                switch (action.Type)
                {
                case DataActionTypes.Insert:
                    repo.Insert(changedEvent);
                    action.TargetId = changedEvent.id; //assign postoperational id
                    break;
                case DataActionTypes.Delete:
                    repo.Delete(changedEvent.id);

                    //do delete
                    break;

                default: // "update"                          
                    repo.Update(changedEvent);
                    break;
                }
            } catch
            {
                action.Type = DataActionTypes.Error;
            }
            return (ContentResult) new AjaxSaveResponse(action);
        }
    }
}

That’s it.

Of course, this is a very basic demo and it doesn’t really display the advantages offered by NHibernate, and still it can be useful by those who are new to NHibernate or DHTMLX Scheduler for .NET.

To continue the tradition, we've included a demo sample with NHibernate:

IMPORTANT: This is not a complete demo. You still need to create a database and change the connection string.

Feel free to comment and share this post with your friends.