In my last article on the topic of database development, I covered performing database migration using MigratorDotNET.

Next, I wanted to look at the mapping process to the object model. I’d already decided I was going to use NHibernate as my ORM, but the detail was in hooking up NHibernate to the database. NHibernate’s XML syntax is pretty straightforward and incredibly powerful, but once again it’s another language i’m forced to deal with – i’m most efficient working in my primary language so the idea of slowing down when dealing with these mapping files by hand was really not in question.

Initially I looked into ActiveRecord (admittedly not into a whole lot of detail) but wasn’t excited by the framework. ActiveRecord performs it’s mappings from objects to database through attributes and it just seemed to me like an abuse of SoC. If i should want to change my ORM (unlikely, but i’m working within that constraint on this project), then it would have to support the same attribute syntax. Having said that however, there is a lot of momentum behind ActiveRecord, so i’m still reserving judgement on it’s applicability.

So apart from ActiveRecord, I went in search of another alternative to the XML mapping and recalled reading about Fluent NHibernate. In a nut-shell, Fluent NHibernate is a replacement for the XML mapping layer in NHibernate by defining the mapping in C#. Essentially the same benefits I got by using MigratorDotNet (type safety, compile-time checking etc) were available for defining my DB->OM mapping. Sweet!

A very quick spike with the project, and I immediately liked what I saw:

	public class NoteMap : ClassMap<Note>
	{
		public NoteMap()
		{
			Id(x => x.NoteId).GeneratedBy.Guid();
			Map(x => x.NoteTitle).WithLengthOf(64);
			Map(x => x.NoteData);
		}
	}

The equivalent XML mapping file (I won’t discuss it in detail in this post) would have been at least twice the size, and more importantly not refactor-friendly.

Because it’s in C# I was easily able to unit-test this mapping, with a little assistance. In fact it was so successful, it helped me discover a bug in my database migration script!

	[TestFixture]
	public class NoteMapping_Test : BaseTestMappings
	{
		[Test]
		public void TestCanAddNote()
		{
			Note note = new Note
			            	{
			            		NoteTitle = "Title",
			            		NoteData = "Data`"
			            	};
			Session.Save(note);

			Session.Flush();
			Session.Clear();
			Note fromDb = Session.Get<Note>(note.NoteId);
			Assert.AreNotSame(note, fromDb);
			Assert.AreEqual(note.NoteData, fromDb.NoteData);
			Assert.AreEqual(note.NoteTitle, fromDb.NoteTitle);
			Assert.AreEqual(note.NoteId, fromDb.NoteId);
		}
	}


	public class BaseTestMappings
	{
		protected SessionSource Source { get; set; }
		protected ISession Session { get; private set; }

		[SetUp]
		public void SetUp()
		{
			Source = new SessionSource(new TestModel());
			Session = Source.CreateSession();
			Source.BuildSchema(Session);
			CreateInitialData(Session);
			Session.Clear();
			Session.Transaction.Begin();
		}

		[TearDown]
		public void TearDown()
		{
			Session.Transaction.Rollback();
			Session.Close();
			Session.Dispose();
		}

		public class TestModel : PersistenceModel
		{
			public TestModel()
			{
				Assembly ass = typeof(NoteMap).Assembly;
				addMappingsFromAssembly(ass);
			}
		}
	}

What’s happening here is that Fluent NHibernate allows me to instantiate an NHibernate instance just by creating a Model. The model contains a list of all of the mappings applicable for my application and I pass that directly into the NHibernate session. Any of my tests which I want connected to a database will now have transaction management and a session for performing querying. I can use this in my application too with just about the exact same code, so instantiate a session and pass in the model.

It works very well and i’ve sucessfully removed the XML file with a type-safe C# mapping engine. The problem this poses, however is now I have two places where I have defined what my data structures look like. One in the MigratorDotNET framework, and the other in FluentNHibernate to map the data model. This means that to make any any change to the model would involve no less than 3 changes – the POCO, FluentNHibernate and MigratorDotNET.

Next time, I want to discuss ways of reducing this friction and streamline the refactoring process.

(There are some websites which i wish to attribute for some of the code and ideas i’ve expressed here but have since lost the links. If you see anything that’s yours, please let me know so I can appropriately credit)

http://weblogs.asp.net/nunitaddin/archive/2008/12/02/testdriven-net-2-18-nunit-2-5-beta.aspx

Jamie covers off some of the new things in NUnit 2.5 which are pretty cool, but the one thing he omitted (and I think is quite awesome) is the Assert.Throws<T>(); assertion.

Previously (NUnit 2.4 and below) you would either have to use the [ExpectedException()] attribute or implement the exception handling logic yourself in your test. Issues with using the ExpectedException attribute are well known. I’m doing this without VS at hand, so forgive me if parts are wrong, but for example:


[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void TestArgumentNullThrowsException()
{
    new MyObject(null);
}
  
  
[Test]
public void TestArgumentNullThrowsException()
{
  bool thrown = false;
  
  try
  {
    new MyObject(null);
  }
  catch (ArgumentNullException e)
  {
    // Check if the message is correct
    thrown = true;
  }
  catch (Exception e)
  {
    throw; // Any unexpected exceptions still get raised up
  }
  finally
  {
    Assert.IsTrue(thrown, "Expected exception should be thrown, but was not");
  }
}

Well with NUnit 2.5, you can lambda the entire thing and the testcase becomes so much simpler:


[Test]
public void TestArgumentNullExceptionIsThrown()
{
  Assert.Throws<ArgumentNullException>( () =>  new MyObject(null)  );
}

…And why is this good for TestDriven.NET? It means I can install NUnit 2.5 and actually use it with TD.NET, instead of using the GUI test runner.