Kash Farooq's software development blog

.NET Developer

Archive for the ‘Fluent NHibernate’ Category

Creating a database schema with Fluent NHibernate

Posted by Kash Farooq on July 17, 2012

If you create your model in C# first, and then want to create a database schema that matches that model, you can do this easily with Fluent NHibernate.

First, you need some sort of Data Access Initialization class.

public class DataAccessInitializer
{
  private static ISessionFactory sessionFactory;
  private readonly FluentConfiguration fluentConfiguration;
  private Configuration nhibernateConfiguration;

  public DataAccessInitializer()
  {
    //Fluently configure nHibernate and save the nHibernate config that has been created by Fluent
    fluentConfiguration = CreateFluentConfiguration().ExposeConfiguration(cfg => nhibernateConfiguration = cfg);
  }

  public Configuration NhibernateConfiguration
  {
    get { return nhibernateConfiguration; }
  }

  public ISessionFactory CreateSessionFactory()
  {
    return sessionFactory ?? (sessionFactory = fluentConfiguration.BuildSessionFactory());
  }

  private static FluentConfiguration CreateFluentConfiguration()
  {
    var entitiesToMapConfiguration = new EntitiesToMapConfiguration();
    return Fluently.Configure()
        .Database(MsSqlConfiguration.MsSql2008
                        .ConnectionString(x => x.Server(".")
                        .Database("nHibernateAndWebSessionManagement")
                        .TrustedConnection()))
        .Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<Movie>(entitiesToMapConfiguration))); //Movie is one of my entities that needs mapping
  }

  //Class to limit the objects Fluent is interested in
  private class EntitiesToMapConfiguration : DefaultAutomappingConfiguration
  {
    public override bool ShouldMap(Type type)
    {
      return type.Namespace == "MovieSearch.DataAccess.Entities"; //only use classes in this namespace.
    }
  }
}

You could use this to create your Session Factory for any app. Note that I’ve created a EntitiesToMapConfiguration class to limit the types that Fluent is interested in. I don’t want NHibernate to start looking for a DataAccessInitializer table.

I’ve done one extra thing that you don’t need if you just want to create sessions from the Session Factory: I’ve called FluentConfiguration.ExposeConfiguration to save the NhibernateConfiguration into a private variable. I have also created a public NhibernateConfiguration property that exposes this so that it can specifically be used by the following code to create the database schema:


[TestFixture]
public class DataAccessTest
{
  private static void BuildSchema(Configuration cfg)
  {
    new SchemaUpdate(cfg).Execute(true, true);
  }

  [Test]
  [Explicit]
  public void CreateSchema()
  {
    var dataAccessService = new DataAccessInitializer();
    dataAccessService.CreateSessionFactory();
    BuildSchema(dataAccessService.NhibernateConfiguration);
  }
}

I’ve wrapped the runner in an NUnit test, and used the ExplicitAttribute to prevent the test from running accidentally – it won’t run if you chose to run all tests in a solution, only if you run that one test explicitly.

Advertisements

Posted in .NET, Fluent NHibernate, NHibernate | Tagged: , , , | Leave a Comment »

Unit Testing with SQL Lite and Fluent NHibernate

Posted by Kash Farooq on January 2, 2011

I used to unit test NHibernate criteria by, essentially, interaction testing.

It’s fairly straight forward to do this (NHibernate provides lots of interfaces that are easy to mock), but the test code ends up just mirroring the production code. Your test would check that CreateCriteria was called, then an Expression was added, then List was called, etc, etc.

If the production code changes (for example, a more efficient criteria is implemented, or HQL is used), the test would need to be completely rewritten. This defeats one of the objectives of TDD – provide an environment in which refactoring can be done safely, with the confidence that the new code does exactly what the old code did.

So, I switched to using SQL Lite to allow my unit tests to actually hit an in-memory database. I think this is perfectly acceptable for simple queries that are not using any DB specific features. The tests are also fast enough to run on a Continuous Build server.

The code in this post uses Fluent NHibernate to configure NHibernate. It allows me to easily configure my production code to use a SQL Lite database via my test code, and to use a production database via my production code.

Let’s start with a very simple Model – the data to be persisted.

namespace SystemUnderTest.Model {
  public class Person {
    public virtual long Id { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual DateTime DateOfBirth { get; set; }
  }
}

Next, we need some code that configures NHibernate using Fluent, and allows me to set the database type to use. Note that the code exposes the Session Factory so I can create a session when needed. It also exposes the NHibernate configuration. I will use this from the unit test to create a schema inside my SQL Lite in-memory database.

namespace SystemUnderTest.DataAccess {
  public class DataSession {
    private readonly IPersistenceConfigurer _dbType;
    public DataSession(IPersistenceConfigurer dbType) {
      _dbType = dbType;
      CreateSessionFactory();
    }

    private ISessionFactory _sessionFactory;
    private Configuration _configuration;

    public ISessionFactory SessionFactory {
      get { return _sessionFactory; }
    }

    public Configuration Configuration {
      get { return _configuration; }
    }

    private void CreateSessionFactory() {
      _sessionFactory = Fluently
      .Configure()
      .Database(_dbType)
      //Only map classes in the Assembly of 'Person' that have a namespace ending in .Model
      .Mappings(m => m.AutoMappings.Add(
         AutoMap.AssemblyOf<Person>().Where(type => type.Namespace.EndsWith(".Model"))))
      .ExposeConfiguration(cfg => _configuration = cfg)
      .BuildSessionFactory();
    }
  }
}

Now, let’s look at a unit test. I will be creating a PersonRepository to save objects, query objects, etc. The test setup for this class needs to tell the production code ‘DataSession’ class to use an in-memory SQL Lite instance, and to build a schema inside this instance based on the configuration created by Fluent NHibernate.

[TestFixture]
public class PersonRepositoryTest {
 private DataSession _dataSession;
 private ISession _session;

 [TestFixtureSetUp]
 public void TestFixtureSetUp() {
    //Use In Memory database, open session and Build Schema inside In Memory database
    _dataSession = new DataSession(SQLiteConfiguration.Standard.InMemory());
    _session = _dataSession.SessionFactory.OpenSession();
    BuildSchema(_session, _dataSession.Configuration);
 }

 public void BuildSchema(ISession session, Configuration configuration) {
   var export = new SchemaExport(configuration);
   export.Execute(true, true, false, session.Connection, null);
 }

 [TestFixtureTearDown]
 public void TestFixtureTearDown() {
   //Clean up after tests have run
   _session.Close();
   _dataSession.SessionFactory.Close();
 }

 [SetUp]
 public void SetUp() {
   CleanTheTables(); //Make sure tables are empty before each test runs
 }
}

Now, a simple test to begin with. Create a person, save it using our PersonRepository class and then make sure we can find it inside the in-memory database.


[Test]
public void SaveAPersonTest() {
  var personRepository = new PersonRepository(_session);
  personRepository.Save(
     new Person{DateOfBirth = new DateTime(1970,1,1),FirstName = "John",LastName = "Smith"});

  //Now get all Person objects from DB and make sure our object has been persisted
  IList<Person> people = _session.CreateCriteria<Person>().List<Person>();
  Assert.That(people.Count,Is.EqualTo(1));
  Assert.That(people[0].FirstName,Is.EqualTo("John"));
}

Simple.

Now for something a little more complicated; something that we could implement using several methods (e.g. using Criteria, HQL, SQL).

[Test]
public void FindPeopleOlderThanCertainAgeTest() {
  var personRepository = new PersonRepository(_session);
  SaveFourPeopleWithTwoOlderThan30(personRepository);

  //Use repository to find people older than 30
  IList<Person> peopleOlderThan30 = personRepository.GetAllPeopleOlderThan(30);
  Assert.That(peopleOlderThan30.Count,Is.EqualTo(2));
  Assert.That(peopleOlderThan30.Count(x=>x.FirstName=="John")==1);
  Assert.That(peopleOlderThan30.Count(x=>x.FirstName=="Bob")==1);
}

This test provides our TDD safeguard. We can implement GetAllPeopleOlderThan any way we like and this test will ensure that it has been implemented correctly. We can refactor the production code at a later date and the test will ensure we haven’t introduced a bug.

For completeness, here is my implemented repository class:

public class PersonRepository {
  private readonly ISession _session;
  public PersonRepository(ISession session) {
    _session = session;
  }

  public void Save(Person person) {
    _session.Save(person);
  }

  public IList<Person> GetAllPeopleOlderThan(int ageInYears) {
    ICriteria criteria = _session.CreateCriteria<Person>();
    DateTime datePersonMustBeBornBefore = DateTime.Now.AddYears(-1*ageInYears);
    criteria.Add(Expression.Le("DateOfBirth", datePersonMustBeBornBefore));
    return criteria.List<Person>();
  }
}

Posted in Fluent NHibernate, NHibernate, Test Driven Development | Tagged: , , | 1 Comment »