• (2 Pages)
  • +
  • 1
  • 2

Fluent NHibernate tutorial Simple ORM application

#1 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Posted 12 March 2010 - 05:34 PM

*
POPULAR

In this tutorial we are going to create a simple ORM (Object relational mapping) application using Fluent NHibernate 1.0 RTM which is external to the NHibernate Core, but is fully compatible with NHibernate version 2.1, and is experimentally compatible with NHibernate trunk.

Fluent NHibernate offers an alternative to NHibernate's standard XML mapping files. Rather than writing XML documents (.hbm.xml files), Fluent NHibernate lets you write mappings in strongly typed C# code. This allows for easy refactoring, improved readability and more concise code.

How does Fluent NHibernate work?
- It moves your mappings into actual code, so they're compiled along with the rest of your application
- Rename refactorings will alter your mappings just like they should, and the compiler will fail on any typos
- It has a conventional configuration system, where you can specify patterns for overriding naming conventions and many other things
- you set how things should be named once, then Fluent NHibernate does the rest

For more info, click the following link: http://wiki.fluentnhibernate.org/



GETTING STARTED:
First thing you need to download NHibernateFluent libraries that can be found here: http://fluentnhibernate.org/
Unzip downloaded file and extract it into a folder of your choice.

Now start Visual Studio and create new windows application project. I named it SimpleOrmApplication. First of all we are going to reference some dll files that Fluent NHibernate needs. Right click on the References in your solution explorer and select Add Reference. Navigate to directory where you have previously extracted your Fluent NHibernate libraries and reference the following dll files:

- FluentNhibernate.dll
- NHibernate.dll
- NHibernate.ByteCode.Castle


Now open our Form1 class in code view and add the following using statements at the top of the class:

using FluentNHibernate;
using NHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Automapping;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Criterion;
using SimpleOrmApplication.Model;



Let's continue with creating our database model... At this stage you have number of options how to define and create your model and a number of tools to help you do that, but I have decided that we are going to keep things as simple as possible. In this tutorial won't create our database entities model with designer, instead our model will be represented only by strongly typed C# classes. So for purpose of this tutorial we are going to create two simple classes named Employee and Post, but before that let us add few new folders to our solution, just to keep things organized. Click on your project in solution explorer and add new folder named Model. The classes I mentioned previously will be created inside this newly created folder, so your structure should look something like this:

Attached Image


Your Post class should look like this:

using System;

namespace SimpleOrmApplication.Model
{
    public class Post
    {
        public virtual int Id { get; set; }
        public virtual string PostCode { get; set; }
        public virtual string PostName { get; set; }
    }
}



Your Employee class should look like this:
using System;

namespace SimpleOrmApplication.Model
{
    public class Employee
    {
        public virtual int Id { get; set; }
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
        public virtual string Address { get; set; }
        public virtual Post Post { get; set; }
        public virtual DateTime DateEmployed { get; set; }
    }
}



Notice that the namespace of this two classes above is SimpleOrmApplication.Model and is named according to our folder structure. This will be important later when we will be creating auto-mappings. I suggest you allways put your database entity classes (like Employee and Post) in a seperate namespace.


Now get back to our Form1 and open it in code view. Add the private static variable of type ISessionFactory and name it sessionFactory. Then add the three methods as shown in code below:

using statements...
...
...

namespace SimpleOrmApplication
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private static ISessionFactory BuildSessionFactory()
        {
            //This method build our session factory -
            //the most important part of our ORM application
        }

        private static AutoPersistenceModel CreateMappings()
        {
            //This method will create our auto-mappings model
        }

        private static void BuildSchema(Configuration config)
        {
            //This method will create/recreate our database
            //This method should be called only once when
            //we want to create our database
        }

        private static ISessionFactory sessionFactory;
    }
}




Update the CreateMappings method with the following code:
private static AutoPersistenceModel CreateMappings()
{
    return AutoMap
        .Assembly(System.Reflection.Assembly.GetCallingAssembly())
        .Where(t => t.Namespace == "SimpleOrmApplication.Model");
}


This method generates auto-mappings for all the classes (entities) that are found in our SimpleOrmApplication.Model namespace. This is the reason why we needed to place our entity classes in its own namespace, that Fluent NHibernate will map only classes contained in this namespace.


Now update our BuildSchema method to look like the code below:
private static void BuildSchema(Configuration config)
{
    new SchemaExport(config).Create(false, true);
}




The last thing we need to do is to configure our Fluent NHibernate, tell it what database provider to use, how to connect to our database and build the session factory. To do this, update the BuildSessionFactory method with the following code:

private static ISessionFactory BuildSessionFactory()
{
    AutoPersistenceModel model = CreateMappings();

    return Fluently.Configure()
        .Database(MsSqlConfiguration.MsSql2005
        .ConnectionString(c => c
            .Server("MYCOMPUTER\\SQLEXPRESS")
            .Database("testdb")
            .Username("test")
            .Password("test")))
        .Mappings(m => m
            .AutoMappings.Add(model))
        .ExposeConfiguration(BuildSchema)
        .BuildSessionFactory();
}



As you can see, we are using Microsoft SQL server 2005 database. If you wanted to use SQL Server 2008 database you only need to change the second line of return statement to look like this: MsSqlConfiguration.MsSql2008 or MsSqlConfiguration.MsSql2000 if you want to use older versions of SQL Server. There are listed all the database providers that are supported by NHibernate:

* Microsoft SQL Server 2008/2005/2000
* Oracle
* Microsoft Access
* Firebird
* PostgreSQL
* DB2 UDB
* MySQL
* SQLite

If you wanted to use the latest PostgreSql 8.4 database , your BuildSessionFactory method would look like this (the rest of the methods stay unchanged):

private static ISessionFactory BuildSessionFactory()
{
    AutoPersistenceModel model = CreateMappings();

    return Fluently.Configure()
        .Database(PostgreSQLConfiguration.PostgreSQL82
        .ConnectionString(c => c
            .Host("localhost")
            .Port(5432)
            .Database("testdb")
            .Username("test")
            .Password("test")))
        .Mappings(m => m
            .AutoMappings.Add(model))
        .ExposeConfiguration(BuildSchema)
        .BuildSessionFactory();
}



If you use older PostgreSql database just change the second line of return statement to look like this: .Database(PostgreSQLConfiguration.PostgreSQL81


Finally add a button to our form and name it btnDoSomeStuff. Double click the button so the VS creates our btnDoSomeStuff_Click method and add in the following code:

private void btnDoSomeStuff_Click(object sender, EventArgs e)
{
    using (ISession session = sessionFactory.OpenSession())
    {
        using (ITransaction transaction = session.BeginTransaction())
        {
            Post p1 = new Post();
            p1.PostCode = "1000";
            p1.PostName = "Ljubljana";

            Post p2 = new Post();
            p2.PostCode = "2000";
            p2.PostName = "Maribor";

            Employee emp = new Employee();
            emp.FirstName = "Alex";
            emp.LastName = "Kecman";
            emp.Address = "Sarhova 34";
            emp.Post = p2;
            emp.DateEmployed = DateTime.Now;

            session.Save(emp);
            session.Save(p1);
            session.Save(p2);

            transaction.Commit();
        }
    }
}



Of course we need to call our BuildSessionFactory method, so update the form's constructor code to look like this.

public Form1()
{
    InitializeComponent();
    sessionFactory = BuildSessionFactory();
}



Before we start our application, there is only one thing left to do... Whether you are creating PostgreSql or SQL Server database (I haven't tested other db providers), you first need to create empty database with no tables in it (Use the PgAdmin or SQL Server Management to do so), so the NHibernate can find its name and recreate it. Be sure to set the owner of the database to user that you specified in your connection parameters within BuildSessionFactory method.

Now we are good to take our application for the first test.


Below I provided few more NHibernate queries, just to get you started. Refere to NHibernate documentation for more info...

private void btnDoSomeStuff_Click(object sender, EventArgs e)
{
    using (ISession session = sessionFactory.OpenSession())
    {
        using (ITransaction transaction = session.BeginTransaction())
        {
            //Get post with id == 2
            int id_post = 2;
            Post p1 = session.Get<Post>(id_post);

            //Get employee with id == 1
            int id_employee = 1;
            Employee emp = session.Get<Employee>(id_employee);

            //Get a list of all posts
            IList<Post> posts = session
                .CreateCriteria(typeof(Post))
                .List<Post>();


            //Get a post by given name
            string post_name = "Maribor";
            Post p2 = session.CreateCriteria(typeof(Post))
                .Add(Expression.Eq("PostName", post_name))
                .UniqueResult<Post>();
        }
    }
}




I hope you enjoyed this tutorial. If you have any question, feel free to ask...

Is This A Good Question/Topic? 5
  • +

Replies To: Fluent NHibernate tutorial

#2 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Posted 13 March 2010 - 11:03 AM

There are few things I forgot to add in my tutorial...

1. If you want to write a query like the one below:

IList<Post> posts = session
.CreateCriteria(typeof(Post))
.List<Post>();


...you need to add the following using statement:

using NHibernate.Criterion;


2. In your entity classes you need to mark your public fields as virtual so the NHibernate Fluent is able to override them...

3. If you want to use PostgreSql database provider, you also need to reference Npgsql.dll

4. When inserting data in database using NHibernate it is preferred that you use transaction. If you look at my example in tutorial, I actually saved Employee before I saved the Post object, although Employee was referencing this Post object. If I didn't use transaction, we would end up having both objects (Employee and Post) saved, but Employee record wouldn't reference any post.

5. If you wanted to use Access as your database provider, you will have to get NHibernate.JetDriver class library somewhere. There is an open source project for this driver at SourceForge, and is also included as NHibernate contrib, but you will need to compile it yourself. I must warn you that there are still some issues with this driver. There are few problems with join syntax in queries that use more than one join. This driver passes 93% of NHibernate tests (there are 23 failing tests).
Was This Post Helpful? 1
  • +
  • -

#3 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Posted 19 March 2010 - 11:19 AM

You can continue to the second part of this tutorial where we are going to implement DAO classes.

link: http://www.dreaminco...howtopic=162793
Was This Post Helpful? 0
  • +
  • -

#4 W3bDev  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 42
  • View blog
  • Posts: 379
  • Joined: 15-March 09

Posted 07 May 2010 - 01:48 PM

Hey FlashM,

I tried your example here, but a MappingException is being thrown on run "No persister for: SimpleOrmApplication.Model.Employee"... Any ideas? This is being run on vs2k10, with an empty db. Thanks for the tutorial.
Was This Post Helpful? 0
  • +
  • -

#5 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Posted 07 May 2010 - 01:56 PM

I think this might be because you need to create an empty database yourself (do not create any tables).
Was This Post Helpful? 0
  • +
  • -

#6 W3bDev  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 42
  • View blog
  • Posts: 379
  • Joined: 15-March 09

Posted 07 May 2010 - 02:04 PM

Yes, there are no tables created.
Was This Post Helpful? 0
  • +
  • -

#7 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Posted 07 May 2010 - 02:15 PM

Still getting the same error?
Was This Post Helpful? 0
  • +
  • -

#8 W3bDev  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 42
  • View blog
  • Posts: 379
  • Joined: 15-March 09

Posted 07 May 2010 - 02:16 PM

View PostFlashM, on 07 May 2010 - 01:15 PM, said:

Still getting the same error?


Yes

Attached File(s)


This post has been edited by W3bDev: 07 May 2010 - 02:17 PM

Was This Post Helpful? 0
  • +
  • -

#9 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Posted 07 May 2010 - 02:35 PM

I'm just unable to attach my zip file. Do you have any mail address so I can send you my version. I'm unable to open yours, since I'm using VS2008.
Was This Post Helpful? 0
  • +
  • -

#10 Guest_thecodefool*


Reputation:

Posted 03 June 2010 - 04:43 AM

Fantastic thanks for the great article

For those of you that have just seen this article:

If you get the above zip file from W3bDev (2 posts up)
you have to change the model classes to be public.

-Hope that saves someone some time.
Was This Post Helpful? 0

#11 Guest_Arpan*


Reputation:

Posted 22 October 2010 - 10:56 PM

Excellent First Step Guide....Helped me a lot. Thanks a ton.
Was This Post Helpful? 0

#12 Guest_HopeToBelieveIn*


Reputation:

Posted 05 January 2011 - 01:03 PM

Hello. Im using PostgreSQL 9.0 with Fluent NHIbernate (binary NHibernate 3.0). VS2010 Framework 4.0
Database is empty.
When im trying to add employee and post to database like this:
session.Save(emp);
session.Save(p1);
session.Save(p2);
I'm recieving this exception:
"The type System.DBNull can not be assigned to a property of type System.Int32 setter of SimpleOrmApplication.Model.employee.Id"
Was This Post Helpful? 1

#13 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Posted 06 January 2011 - 01:56 AM

This was a quick fix of your solution that you sent to my mail account:

OK, this was just a quick check of your solution and I kind of fixed it...

In your BuildSessionFactory method I updated this line of code from this:

.Database(PostgreSQLConfiguration.Standard

into this:

.Database(PostgreSQLConfiguration.PostgreSQL82

Then I also added Mono.Security.dll reference to the project and everything worked as it should.
Remember to create an empty database with assigned user in PostgreSQL first.

Let me know if this worked for you as well.

best regards,
Kecman Ales

This post has been edited by FlashM: 06 January 2011 - 01:57 AM

Was This Post Helpful? 1
  • +
  • -

#14 Guest_HopeToBelieveIn*


Reputation:

Posted 06 January 2011 - 08:59 AM

It worked!
Thanks a lot. This topic is extremly useful. Helped me a lot.

But iv got a little question: why every time when i insert data into this database it makes new tables.
For example in table employees iv got

id first_name last_name

1 robert polson
2 pavel zadov
3 scott ridly

and when i insert new employee('alex','moran') using FNHibernate it deletes all data in table and makes it

id first_name last_name

1 alex moran

This post has been edited by HopeToBelieveIn: 06 January 2011 - 08:59 AM

Was This Post Helpful? 1

#15 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Posted 06 January 2011 - 09:18 AM

I think you need to comment or remove this line of code:

.ExposeConfiguration(BuildSchema)

The thing is that this line of code triggers database creation... You should have this line of code only the first time you create your database and then remove it so that database is not created each time a new session is built.
Was This Post Helpful? 2
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2