NHibernate

Post 19 of 21

NHibernate is a mature, open source object-relational mapper for the .NET framework. It’s actively developed , fully featured and used in thousands of successful projects.

 

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:

01 using System;
02 using System.Collections.Generic;
03 using System.Linq;
04 using NHibernate.Linq;
05
06 namespace SimpleNHibernateClient.ConsoleApplication
07 {
08     class Program
09     {
10         static void Main(string[] args)
11         {
12             Console.WriteLine("Hello NHibernate");
13         }
14
15     }
16
17     public class Car
18     {
19         public virtual int Id { getset; }
20         public virtual string Title { getset; }
21         public virtual string Description { getset; }
22         public virtual Make Make { getset; }
23         public virtual Model Model { getset; }
24     }
25
26     public class Make
27     {
28         public virtual int Id { getset; }
29         public virtual string Name { getset; }
30         public virtual IList Models { getset; }
31     }
32
33     public class Model
34     {
35         public virtual int Id { getset; }
36         public virtual string Name { getset; }
37         public virtual Make Make { getset; }
38     }
39
40
41 }

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 magicReferences(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.

01 using FluentNHibernate.Mapping;
02
03 namespace SimpleNHibernateClient.ConsoleApplication
04 {
05     public class CarMap : ClassMap<Car>
06     {
07         public CarMap()
08         {
09             Id(x => x.Id);
10             Map(x => x.Title);
11             Map(x => x.Description);
12             References(x => x.Make).Column("MakeId");
13             References(x => x.Model).Column("ModelId");
14             Table("Car");
15         }
16     }
17
18     public class MakeMap : ClassMap<Make>
19     {
20         public MakeMap()
21         {
22             Id(x => x.Id);
23             Map(x => x.Name);
24             HasMany(x => x.Models)
25                 .KeyColumn("MakeId");
26             Table("Make");
27         }
28     }
29
30    public class ModelMap : ClassMap<Model>
31    {
32        public ModelMap()
33        {
34            Id(x => x.Id);
35            Map(x => x.Name);
36            References(x => x.Make)
37                .Column("MakeId");
38            Table("Model");
39        }
40    }
41 }

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.

01 using FluentNHibernate.Cfg;
02 using FluentNHibernate.Cfg.Db;
03 using NHibernate;
04 using NHibernate.Tool.hbm2ddl;
05
06 namespace SimpleNHibernateClient.ConsoleApplication
07 {
08     public class NHibernateHelper
09     {
10         private static ISessionFactory _sessionFactory;
11
12         private static ISessionFactory SessionFactory
13         {
14             get
15             {
16                 if (_sessionFactory == null)
17                     InitializeSessionFactory();
18                 
19                 return _sessionFactory;
20             }
21         }
22
23         private static void InitializeSessionFactory()
24         {
25             _sessionFactory = Fluently.Configure()
26                 .Database(MsSqlConfiguration.MsSql2008
27                               .ConnectionString(
28                                   @"Server=localhost\SQLExpress;Database=SimpleNHibernate;Trusted_Connection=True;")
29                               .ShowSql()
30                 )
31                 .Mappings(m =>
32                           m.FluentMappings
33                               .AddFromAssemblyOf<Car>())
34                 .ExposeConfiguration(cfg => new SchemaExport(cfg)
35                                                 .Create(truetrue))
36                 .BuildSessionFactory();
37         }
38
39         public static ISession OpenSession()
40         {
41             return SessionFactory.OpenSession();
42         }
43     }
44 }

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. theCreate(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.

01 using System;
02 using System.Linq;
03 using NHibernate.Linq;
04
05 namespace SimpleNHibernateClient.ConsoleApplication
06 {
07     class Program
08     {
09         static void Main(string[] args)
10         {
11             using (var session = NHibernateHelper.OpenSession())
12             {
13                 using (var transaction = session.BeginTransaction())
14                 {
15                     var make = new Make
16                     {
17                         Name = "Ford"
18                     };
19                     session.Save(make);
20
21                     transaction.Commit();
22                     Console.WriteLine("Created Make: " + make.Name);
23
24                 }
25             }
26         }
27
28
29     }
30 }

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 thesession.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.

01 using System;
02 using System.Linq;
03 using NHibernate.Linq;
04
05 namespace SimpleNHibernateClient.ConsoleApplication
06 {
07     class Program
08     {
09         static void Main(string[] args)
10         {
11             using (var session = NHibernateHelper.OpenSession())
12             {
13                 var makeQuery = (from make in session.Query<Make>()
14                                  where make.Name == "Ford"
15                                  select make).Single();
16
17                 Console.WriteLine("Read Make: " + makeQuery.Name);
18                 
19             }
20         }
21
22     }
23 }

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.

01 using System;
02 using System.Linq;
03 using NHibernate.Linq;
04
05 namespace SimpleNHibernateClient.ConsoleApplication
06 {
07     class Program
08     {
09         static void Main(string[] args)
10         {
11             
12             using (var session = NHibernateHelper.OpenSession())
13             {
14                 Make makeIPreparedEariler = session.Query<Make>()
15                     .Where(m => m.Name == "Ford")
16                     .Select(m => m).Single();
17
18                 makeIPreparedEariler.Name = "FORD";
19
20                 using (var transaction = session.BeginTransaction())
21                 {
22                     session.SaveOrUpdate(makeIPreparedEariler);
23                     transaction.Commit();
24                     Console.WriteLine("Updated Make: " + makeIPreparedEariler.Name);
25                 }
26             }
27         }
28
29
30     }
31 }

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.

01 using System;
02 using System.Linq;
03 using NHibernate.Linq;
04
05 namespace SimpleNHibernateClient.ConsoleApplication
06 {
07     class Program
08     {
09         static void Main(string[] args)
10         {
11
12             using (var session = NHibernateHelper.OpenSession())
13             {
14                 Make makeIPreparedEariler = session.Query<Make>()
15                         .Where(m => m.Name == "Ford")
16                         .Select(m => m)
17                         .Single();
18
19                 using (var transaction = session.BeginTransaction())
20                 {
21                     session.Delete(makeIPreparedEariler);
22                     transaction.Commit();
23                     Console.WriteLine("Deleted Make: " + makeIPreparedEariler.Name);
24                 }
25             }
26         }
27
28
29     }
30 }

 

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

001 using System;
002 using System.Collections.Generic;
003 using System.Linq;
004 using NHibernate.Linq;
005
006 namespace SimpleNHibernateClient.ConsoleApplication
007 {
008     class Program
009     {
010         static void Main(string[] args)
011         {
012             //Create
013             Create("Ford");
014             Create("Mercedes");
015             
016             //Read
017             var mercedes = Read("Mercedes");
018             
019             //Update
020             mercedes.Name = "Mercedes Benz";
021             Update(mercedes);
022             
023             //Delete
024             Delete(mercedes);
025
026
027             Console.ReadLine();
028         }
029
030         private static void Delete(Make existingMake)
031         {
032             using (var session = NHibernateHelper.OpenSession())
033             {
034                 using (var transaction = session.BeginTransaction())
035                 {
036                     session.Delete(existingMake);
037                     transaction.Commit();
038                     Console.WriteLine("Deleted Make: " + existingMake.Name);
039                 }
040             }           
041         }
042
043         private static void Update(Make newMakeName)
044         {
045             using(var session = NHibernateHelper.OpenSession())
046             {
047                 using (var transaction = session.BeginTransaction())
048                 {
049                     session.SaveOrUpdate(newMakeName);
050                     transaction.Commit();
051                     Console.WriteLine("Updated Make: " + newMakeName.Name);
052                 }
053             }
054         }
055
056         private static Make Read(string makeName)
057         {
058             using (var session = NHibernateHelper.OpenSession())
059             {
060                 var makeQuery = (from make in session.Query<Make>()
061                                  where make.Name == makeName
062                                  select make).Single();
063
064                 Console.WriteLine("Read Make: " + makeQuery.Name);
065                 return makeQuery;
066             }
067         }
068
069         private static void Create(string carMake)
070         {
071             using (var session = NHibernateHelper.OpenSession())
072             {
073                 using (var transaction = session.BeginTransaction())
074                 {
075                     var make = new Make
076                                    {
077                                        Name = carMake
078                                    };
079                     session.Save(make);
080
081                     transaction.Commit();
082                     Console.WriteLine("Created Make: " + make.Name);
083
084                 }
085             }
086         }
087     }
088
089     public class Car
090     {
091         public virtual int Id { getset; }
092         public virtual string Title { getset; }
093         public virtual string Description { getset; }
094         public virtual Make Make { getset; }
095         public virtual Model Model { getset; }
096     }
097
098     public class Make
099     {
100         public virtual int Id { getset; }
101         public virtual string Name { getset; }
102         public virtual IList<Model> Models { getset; }
103     }
104
105     public class Model
106     {
107         public virtual int Id { getset; }
108         public virtual string Name { getset; }
109         public virtual Make Make { getset; }
110     }
111 }

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..

c

 

This article was written by admin

Menu