NHibernate 3.0 Tutorial with Fluent NHibernate and Linq 2 NHibernate



This is a quickstart tutorial for getting up and running with NHibernate 3.0 using Linq to NHibernate and Fluent NHibernate for configuration. I've also made a Fluent NHibernate Video Tutorial if you'd prefer to watch a screencast.

You're going to need:

  1. VS2010 - Express edition will do. (we're going to be writing a Console Application)
  2. SQL Server 2008 - Express edition should do
  3. NHibernate 3.0 download this tutorial was written with NHibernate 3.0.0
  4. Fluent NHibernate Stable PreRelease binary v1.x build#694
  5. Download Source for this tutorial

 

Step 1 - Create a Console Project & Extract the DLLs from the Zip files

I've called it SimpleNHibernateClient on my machine. Then extract the .dlls from NHibernate-3.0.0.GA-bin.zip\Required_Bins into your lib folder.

Then also extract the .dlls from the fluentnhibernate-NH3.0-binary-1.2.0.694.zip file also into your lib folder. You'll probably find that the fluent zip already contains the required NHibernate .dlls don't worry it should be fine.

Step 2 - Add the References to the relevant .dlls

Your references should look something like this:

Step 3 - Create Some Entity Classes

Next create some entity classes in your project. Now be sure here to make the properties public virtual NHibernate needs the entities properties to be virtual so it can work its magic and pull the information from the database at runtime.

Your code should look something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using NHibernate.Linq;

namespace SimpleNHibernateClient.ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello NHibernate");
        }

    }

    public class Car
    {
        public virtual int Id { get; set; }
        public virtual string Title { get; set; }
        public virtual string Description { get; set; }
        public virtual Make Make { get; set; }
        public virtual Model Model { get; set; }
    }

    public class Make
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual IList Models { get; set; }
    }

    public class Model
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual Make Make { get; set; }
    }


}

Now we've got all your entities in the same file as your actual program. Obviously this isn't best practice, so it'd be good if you extracted them out to their own files.

Step 4 - Create an Empty Database

I did this though Server Explorer and just created an empty Sql2008 Express database.

Step 5 - Create the Database Mappings

Ok, so now you have to tell NHibernate how to map your entities to the database. We're going to use the Fluent NHibernate interface to do this, so all configuration is in code. There are other ways of doing this. You could use xml configuration file .hbm (Hibernate Mapping files) or you could even use attributes.

We're going to use Fluent because it lets us keep our entity POCO's really clean and simple.

Create another class such as CarMap in my example and inherit for ClassMap<Car> this is what lets Fluent NHibernate know to use these mappings with the Car class you've just defined. If you look at the configuration,  it's saying what's the Id field. Handily called Id in this example. Also note the real magic References(x=>x.Make).Column("MakeId") here we're telling NHibernate that a Car has a Make and it's realted by the MakeId column. NHibernate will generate a default column name if you want, I'm doing it for affect. We also specify the table name Table("Car") we don't really need to do this, but we've got that extra little bit of control if we want.

using FluentNHibernate.Mapping;

namespace SimpleNHibernateClient.ConsoleApplication
{
    public class CarMap : ClassMap<Car>
    {
        public CarMap()
        {
            Id(x => x.Id);
            Map(x => x.Title);
            Map(x => x.Description);
            References(x => x.Make).Column("MakeId");
            References(x => x.Model).Column("ModelId");
            Table("Car");
        }
    }

    public class MakeMap : ClassMap<Make>
    {
        public MakeMap()
        {
            Id(x => x.Id);
            Map(x => x.Name);
            HasMany(x => x.Models)
                .KeyColumn("MakeId");
            Table("Make");
        }
    }

   public class ModelMap : ClassMap<Model>
   {
       public ModelMap()
       {
           Id(x => x.Id);
           Map(x => x.Name);
           References(x => x.Make)
               .Column("MakeId");
           Table("Model");
       }
   }
}

That's that, don't worry we're nearly there.

Step 6 - Configuring with Fluent NHiberate

Next we need to tell NHibernate how to connect to the database, aka the ConnectionString and a few other bits of NHibernate magic.

using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Tool.hbm2ddl;

namespace SimpleNHibernateClient.ConsoleApplication
{
    public class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;

        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                    InitializeSessionFactory();
                
                return _sessionFactory;
            }
        }

        private static void InitializeSessionFactory()
        {
            _sessionFactory = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008
                              .ConnectionString(
                                  @"Server=localhost\SQLExpress;Database=SimpleNHibernate;Trusted_Connection=True;")
                              .ShowSql()
                )
                .Mappings(m =>
                          m.FluentMappings
                              .AddFromAssemblyOf<Car>())
                .ExposeConfiguration(cfg => new SchemaExport(cfg)
                                                .Create(true, true))
                .BuildSessionFactory();
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }
}

There's quite a bit going on here. .Database(MsSqlConfiguration.MsSql2008 is where we tell NHibernate to use the SQL Server driver, there are numerous others, including MySql and SQLLite which are the popular one's I'm aware of. The .ConnectionString is obvious we're connecting to the database we defined above.

The .ShowSql() is optional this makes NHibernate spit out the SQL it generates to the console, which is handy if you're trying to debug what the hell it's doing.

.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Car>()) tells NHibernate to reflect over the Assembly that contains our Car type (which will be our console apps exe) and look for the appropriate mapping files. which will be all the files that inherit  ClassMap<T>

The next bit is again optional .ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true,true)) tells NHibernate to actually create the tables in the database if they're not there. You don't really want to leave this on otherwise everytime you run your app it'll drop the tables with all our Cars in them and recreate them. the Create(true,true) also refers to whether to show the SQL generated to drop the tables, which we've turned on so we can see it work its magic.

Finally we BuildSessionFactory() which well er Builds the session factory and we assign it to a static variable so as to only use one Session for the lifetime of our application if that makes sense. I'd recommend futher reading on the lifetim of the session. When starting with NHibernate it was the session that caused me the most confusion.

Step 7 - CRUD - Create

Ok so now we're ready to simply prove the basics work. Firstly lets perform an INSERT into the database.

The code below demonstrates this nicely.

using System;
using System.Linq;
using NHibernate.Linq;

namespace SimpleNHibernateClient.ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    var make = new Make
                    {
                        Name = "Ford"
                    };
                    session.Save(make);

                    transaction.Commit();
                    Console.WriteLine("Created Make: " + make.Name);

                }
            }
        }


    }
}

Notice we're using the Session we just new up a Make class simply give it a name and then session.Save(make) but note that it doesn't actually get added to the database until you Commit the Transaction.

There's a simple order here:

  1. Open Session
  2. Begin Transaction
  3. Do Something
  4. Commit the Transaction
  5. Close the transaction
  6. Close the Session

Now because we have a using statement we're automatically calling Dispose on the Transaction and the session. The session.save(make) figures out the appropriate SQL to generate for us. Magic.

Step 8 - CRUD - Read with Linq 2 NHibernate

Onto the Read operation. For this we'll use a bit of Linq to make life any easier to read. Look familiar, it's much the same as before. The real magic bit is the session.Query<Make>() this is an Extension method that will only be available if you've got using NHibernate.Linq at the top don't forget it. From that point onwards you can right Linq happily as we see here we return the Make which has a name of Mercedes.

using System;
using System.Linq;
using NHibernate.Linq;

namespace SimpleNHibernateClient.ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                var makeQuery = (from make in session.Query<Make>()
                                 where make.Name == "Ford"
                                 select make).Single();

                Console.WriteLine("Read Make: " + makeQuery.Name);
                
            }
        }

    }
}

Step 9 - CRUD - Update

Next comes update which is very nearly identical to create. The only diference is the session.SaveOrUpdate(make) which asks NHibernate to figure out whether this entity should be created or updated. Updated in our case.

using System;
using System.Linq;
using NHibernate.Linq;

namespace SimpleNHibernateClient.ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            
            using (var session = NHibernateHelper.OpenSession())
            {
                Make makeIPreparedEariler = session.Query<Make>()
                    .Where(m => m.Name == "Ford")
                    .Select(m => m).Single();

                makeIPreparedEariler.Name = "FORD";

                using (var transaction = session.BeginTransaction())
                {
                    session.SaveOrUpdate(makeIPreparedEariler);
                    transaction.Commit();
                    Console.WriteLine("Updated Make: " + makeIPreparedEariler.Name);
                }
            }
        }


    }
}

So in this case we've passed the Mercedes make object we've created above and simply changed it's Name property to "Mercedes Benz" simple.

Step 10 - CRUD - Delete

And finally to delete, again really easy session.Delete(make) just what you probably expected. Just remember that anything that actually modifies data in someway whether it's a create, update or delete should probably go inside of a transaction so it can be rolled back safefully if the operation fails. Not that it will but just incase.

using System;
using System.Linq;
using NHibernate.Linq;

namespace SimpleNHibernateClient.ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {

            using (var session = NHibernateHelper.OpenSession())
            {
                Make makeIPreparedEariler = session.Query<Make>()
                        .Where(m => m.Name == "Ford")
                        .Select(m => m)
                        .Single();

                using (var transaction = session.BeginTransaction())
                {
                    session.Delete(makeIPreparedEariler);
                    transaction.Commit();
                    Console.WriteLine("Deleted Make: " + makeIPreparedEariler.Name);
                }
            }
        }


    }
}

 

That all for now, Good luck and have fun with NHibernate. I should point out there's loads of good resources online for NHibernate I strongly recommend you have a look. The documentation is pretty good, well I thought it was.

 

Complete

using System;
using System.Collections.Generic;
using System.Linq;
using NHibernate.Linq;

namespace SimpleNHibernateClient.ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            //Create
            Create("Ford");
            Create("Mercedes");
            
            //Read
            var mercedes = Read("Mercedes");
            
            //Update
            mercedes.Name = "Mercedes Benz";
            Update(mercedes);
            
            //Delete
            Delete(mercedes);


            Console.ReadLine();
        }

        private static void Delete(Make existingMake)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    session.Delete(existingMake);
                    transaction.Commit();
                    Console.WriteLine("Deleted Make: " + existingMake.Name);
                }
            }            
        }

        private static void Update(Make newMakeName)
        {
            using(var session = NHibernateHelper.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    session.SaveOrUpdate(newMakeName);
                    transaction.Commit();
                    Console.WriteLine("Updated Make: " + newMakeName.Name);
                }
            }
        }

        private static Make Read(string makeName)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                var makeQuery = (from make in session.Query<Make>()
                                 where make.Name == makeName
                                 select make).Single();

                Console.WriteLine("Read Make: " + makeQuery.Name);
                return makeQuery;
            }
        }

        private static void Create(string carMake)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    var make = new Make
                                   {
                                       Name = carMake
                                   };
                    session.Save(make);

                    transaction.Commit();
                    Console.WriteLine("Created Make: " + make.Name);

                }
            }
        }
    }

    public class Car
    {
        public virtual int Id { get; set; }
        public virtual string Title { get; set; }
        public virtual string Description { get; set; }
        public virtual Make Make { get; set; }
        public virtual Model Model { get; set; }
    }

    public class Make
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual IList<Model> Models { get; set; }
    }

    public class Model
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual Make Make { get; set; }
    }
}

The Deliberate Mistake

Please see this post from Ayende for my details on how better to use the Session, and thanks to the commenter below for pointing it out.

http://ayende.com/Blog/archive/2011/03/01/new-profiler-feature-avoid-writes-from-multiple-sessions-in-the.aspx

Download The Code

SimpleNHibernateClient.zip (15.71 mb)

Recommended Reading

If you really want to understand NHibernate you'll want to have a look at these. NHibernate in Action atleast my copy is for NHibernate 2 but it's still relevant and an interesting read.

References

Good luck and happy NHibernating..


blog comments powered by Disqus

Search

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2014