Simple CRUD with NHibernate and Windows Form

Niladri.Biswas
Posted by in Others category on for Beginner level | Points: 250 | Views : 33350 red flag

A demonstration for the beginners as how to start with NHibernate in windows form


 Download source code for Simple CRUD with NHibernate and Windows Form

Introduction

Today, we will get ourself introduce with an Object Relational Mapper (ORM) technology through NHibernate.The main purpose of any ORM technology is to map the data representation from an object model to a relational data model.In this article, we will address the same with the help of NHibernate through an windows application.

Objective

In this article we will perform a simple CRUD operation with Player entity though winfows application and NHibernate

Where to get NHibernate?

Get the latest NHibernate from here

What to do next?

Once downloaded,unzip the zipped file in a suitable folder location.We will find the NHibernate.dll,Log4net.dll under Required_Bins folder.

Step 1: Create the Relational Model

The first step is to create a Player table in the database.So let us execute the below script that will help us to create the Player table in TestDB database.

CREATE DATABASE TestDB
GO
USE [TestDB]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Player]') AND type in (N'U'))
DROP TABLE [dbo].[Player]
GO

CREATE TABLE [dbo].[Player](
[PlayerId] [int] IDENTITY(1,1) NOT NULL,
[PlayerName] [varchar](50) NOT NULL,
[PlayerAge] [int] NOT NULL,
[DOJ] [datetime] NOT NULL,
[BelongsTo] [varchar](50) NOT NULL,
CONSTRAINT [PK_Player] PRIMARY KEY CLUSTERED
(
[PlayerId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

Executing the script will create the player table that will look as under

Step 2: Create a Windows Form Application

Next,let's open up VS2010 and create a project of type "Windows Form application"

Step 3: Create the Object Moddel

Now, let us create the Player object model.For doing so, let us create a class file "Player.cs" and add the below attributes to it

using System;

namespace NHibernateExperiment

{

public class Player

{

public int PlayerId { get; set; }

public string PlayerName { get; set; }

public int PlayerAge { get; set; }

public DateTime DOJ { get; set; }

public string BelongsTo { get; set; }

}

}

Step 4:Create an XML Mapping File(names end with .hbm.xml)

An xml mapping class is needed where we need to map maps between .NET-Classes (Objects) and relational data (Database-Tables).In this file we specify as which columns of the relational table will match with which attribute of the object model.

For this, let us right click on the project -> Add -> New item->XML file.Let us name it as named "Player.hbm.xml"

Add the below to it

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

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">

<class name="NHibernateExperiment.Player, NHibernateExperiment" lazy="true">

<id name="PlayerId">

<generator class="native"/>

</id>

<property name="PlayerName" column ="PlayerName"/>

<property name="PlayerAge" column ="PlayerAge"/>

<property name="DOJ" column="DOJ"/>

<property name="BelongsTo" column="BelongsTo"/>

</class>

</hibernate-mapping>

Let us visit as what it does.

<class name="NHibernateExperiment.Player, NHibernateExperiment" lazy="true">

This line indicates which is the Object Model(here Player) and it belongs to the NHibernateExperiment namespace.That means we need to specify a fully qualified class name followed by the namespace

The next attribute tells us whether we want a lazy initialization of our object model.Setting the property value to true will allow it to load lazily and it is rather a good practice.

<id name="PlayerId">

<generator class="native"/>

</id>

PlayerId is a Primary Key and is auto generated field.

<property name="PlayerName" column ="PlayerName"/>

It says that the column name is "PlayerName" and the corresponding object attribute name is also "PlayerName". If suppose we have given the object attribute name as "OurPlayerName", then the mapping will be

<property name="OurPlayerName" column ="PlayerName"/>

Likewise, if the column name in the relational model is changed to "Player Name", then the mapping will be

<property name="PlayerName" column ="Player Name"/>

Hope the mapping section is clear

Step 6: Create a configuration file

We need to tell NHibernate as where the database resides for which we need an app.config file here and it is as under

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

<configuration>

<configSections>

<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />

</configSections>

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">

<session-factory>

<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>

<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>

<property name="connection.connection_string">Server=.;database=TestDB;Integrated Security=SSPI;</property>

<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>

<property name="show_sql">false</property>

<property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>

</session-factory>

</hibernate-configuration>

</configuration>

Step 7:

Add a reference to NHibernate.dll to the project

Step 8: Create a Session Factory

NHibernate expects an NHibernate-Session-object for accessing the database.Henceforth, we need to create a Session Factory for this.

Create a class call "SessionFactory.cs" and add the below code to it

using System;

using System.Reflection;

using NHibernate;

using NHibernate.Cfg;

using System.ServiceModel.Channels;

using System.Configuration;

namespace NHibernateExperiment

{

public sealed class SessionFactory

{

private static volatile ISessionFactory iSessionFactory;

private static object syncRoot = new Object();

public static ISession OpenSession

{

get

{

if (iSessionFactory == null)

{

lock (syncRoot)

{

if (iSessionFactory == null)

{

Configuration configuration = new Configuration();

configuration.AddAssembly(Assembly.GetCallingAssembly());

iSessionFactory = configuration.BuildSessionFactory();

}

}

}

return iSessionFactory.OpenSession();

}

}

}

}

Each application should create only one instance of ISessionFactory per database it access since it is very expensive.

Step 9: Design the Windows Form

Design a windows form as under

Write the Functions

(A)Display button function

private void btnDisplay_Click(object sender, EventArgs e)

{

try

{

GetPlayerInfo();

}

catch (Exception ex)

{

throw ex;

}

}


The GetPlayerInfo() function is define as under

private void GetPlayerInfo()

{

using (ISession session = SessionFactory.OpenSession)

{

IQuery query = session.CreateQuery("FROM Player");

IList pInfos = query.List<Player>();

dgView.DataSource = pInfos;

}

}

Once a new session is being created, we create a new instance of Query for the given query string ("FROM Player").That we convert to the strongly typed entity which is Player here (query.List()). Finally we bind the result to the grid

(B)Insert button function

private void btnInsert_Click(object sender, EventArgs e)

{

Player playerData = new Player();

SetPlayerInfo(playerData);

using (ISession session = SessionFactory.OpenSession)

{

using (ITransaction transaction = session.BeginTransaction())

{

try

{

session.Save(playerData);

transaction.Commit();

GetPlayerInfo();

}

catch (Exception ex)

{

transaction.Rollback();

throw ex;

}

}

}

}

The SetPlayerInfo() function is define as under

private void SetPlayerInfo(Player playerData)

{

playerData.PlayerName = txtPlayerName.Text;

playerData.DOB = Convert.ToDateTime(dpDOB.Text);

playerData.PlayerAge = playerData.DOB.Subtract(DateTime.Now).Days / 365;

playerData.BelongsTo = cmbBelongsTo.SelectedItem.ToString();

}

The Save method (session.Save(playerData)) accepts a transient instance of a persistent class and generates an identifier after saving the record.Commit ends the unit of work and flushes the associated ISession.The record will be rolled back if any discrepancy happens

(C)Update button function

private void btnUpdate_Click(object sender, EventArgs e)

{

using (ISession session = SessionFactory.OpenSession)

{

using (ITransaction transaction = session.BeginTransaction())

{

try

{

IQuery query = session.CreateQuery("FROM Player WHERE PlayerName = '" + txtPlayerName.Text + "'");

Player playerData = query.List<Player>()[0];

SetPlayerInfo(playerData); //changes the data

session.Update(playerData); //update the new data

transaction.Commit(); //commit the data

GetPlayerInfo(); //display the updated record

}

catch (Exception ex)

{

transaction.Rollback();

throw ex;

}

}

}

}

First we get the record that needs to be updated by firing the query.Then set the new value to the Player Entity and finally Update the record and commit it

(D)Delete button function

private void btnDelete_Click(object sender, EventArgs e)

{

using (ISession session = SessionFactory.OpenSession)

{

using (ITransaction transaction = session.BeginTransaction())

{

try

{

IQuery query = session.CreateQuery("FROM Player WHERE PlayerName = '" + txtPlayerName.Text + "'");

Player playerData = query.List<Player>()[0];

session.Delete(playerData); //delete the record

transaction.Commit(); //commit it

GetPlayerInfo(); //display the new collection

}

catch (Exception ex)

{

transaction.Rollback();

throw ex;

}

}

}

}

Delete function is similar to the Update one.First we get the record that needs to be removed by firing the query in the Player Entity and finally Delete the record and commit it

Finally testing it

Looks fine.Right?.So let us run the application by pressing F5.Enter some relevant value to the respective placeholders and click on the "Insert button"

ERROR!!!!!

Unable to load type 'NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu' during configuration of proxy factory class.
Possible causes are:
- The NHibernate.Bytecode provider assembly was not deployed.
- The typeName used to initialize the 'proxyfactory.factory_class' property of the session-factory section is not well formed.

Solution:
Confirm that your deployment folder contains one of the following assemblies:
NHibernate.ByteCode.LinFu.dll
NHibernate.ByteCode.Castle.dll

Since the Lazy loading is on and the reference for that is not set, henceforth is the complain.So let us follow the solution by adding the NHibernate.ByteCode.LinFu.dll which is found under the Required_For_LazyLoading\LinFu

Let us again run the application by supplying proper input

ERROR!!!!!

No persister for: NHibernateExperiment.Player

It failed at session.Save(playerData); line.This happens because the members persisted in the database have to be virtual since we are using lazy loading.So we need to mark the properties of the "Player" Entity as virtual

using System;

namespace NHibernateExperiment

{

public class Player

{

virtual public int PlayerId { get; set; }

virtual public string PlayerName { get; set; }

virtual public int PlayerAge { get; set; }

virtual public DateTime DOJ { get; set; }

virtual public string BelongsTo { get; set; }

}

}

Let us again run the application by supplying proper input.This time it worked as the output is as under(Insert Operation)

Try to do the Update and Delete operation and that will work too.

Conclusion

This is only an introduction for beginners as how to start with NHibernate.There are more to it which we will address in later articles.Hope you enjoyed it.Zip file is attached for your reference.

Page copy protected against web site content infringement by Copyscape

About the Author

Niladri.Biswas
Full Name: Niladri Biswas
Member Level: Platinum
Member Status: Member
Member Since: 10/25/2010 11:04:24 AM
Country: India
Best Regards, Niladri Biswas
http://www.dotnetfunda.com
Technical Lead at HCL Technologies

Login to vote for this post.

Comments or Responses

Login to post response

Comment using Facebook(Author doesn't get notification)