Creating a common generic and extensible NHiberate Repository

In my previous post Conversation Per Business Transaction using PostSharp and IoC I dealt with the session management aspect of NHiberate however by the end of my development of the business conversation aspect I realized that my current data provider scheme created a lot of duplicate code. As we all know any code that is duplicated becomes a nightmare to maintain so I went through and refactored first a truly generic repository.

public interface IRepository<T>
{
    ICriteria GetAll();
    T Get<U>(U id);
    void Save(T obj);
    ICriteria GetRange(int resultSet, int rangeSize);
}

This is a rather basic interface that will handle the most common operations to my data providers, currently it can handle getting all of the items in my database for a type, a page collection into the list of items in my database, get a specific item and save a new item (or update an existing item). The only minorly unsightly part is the Get<U> method this just allows passing any type of ID instead of declaring it as int statically.

On to implementing the interface:

public class Repository<T> : IRepository<T>
{
    private readonly IConversation _conversation;

    public Repository(IConversation conversation)
    {
        _conversation = conversation;
    }

    #region IRepository<T> Members

    ICriteria IRepository<T>.GetAll()
    {
        return _conversation.Session.CreateCriteria(typeof (T))
            //.SetCacheable(true)
            //.SetCacheMode(CacheMode.Normal)
            ;
    }

    T IRepository<T>.Get<U>(U id)
    {
        return _conversation.Session.Get<T>(id);
    }

    void IRepository<T>.Save(T obj)
    {
        _conversation.Session.SaveOrUpdate(obj);
    }

    ICriteria IRepository<T>.GetRange(int resultSet, int rangeSize)
    {
        return _conversation.Session.CreateCriteria(typeof (T))
            //.SetCacheable(true)
            //.SetCacheMode(CacheMode.Normal)
            .SetFirstResult(resultSet*rangeSize)
            .SetMaxResults(rangeSize - 1)
            ;
    }

    #endregion
}

This class contains rather basic interactions with NHiberate, if you’re not familiar with the CreateCriteria querying method in NHibernate take a look at Chapter 12. Criteria Queries. Other than that I can at an application level enable or disable output caching for my generic repository, currently I’m still working on getting my second level caching implementation working so right now I have it disabled as you can see it’s commented out.

By returning the ICriteria from the repository it allows us to pass on the full power of NHibernate and allow us to create further data provider specific queries.

Next I created an abstract base class for my actual data providers:

public abstract class DataProviderBase<T>
{
    protected readonly IConversation _conversation;
    protected readonly IRepository<T> _repoistory;

    protected DataProviderBase(IConversation conversation)
    {
        _conversation = conversation;
        _repository = new Repository<T>(_conversation);
    }
}

This base class just holds the fields for the business conversation (or ISession) and my newly created generic repository. Now on to my true concrete implementation of my data provider:

public class EmployeeDataProvider : DataProviderBase<Employee>, IEmployeeDataProvider
{
    [InjectionConstructor]
    public EmployeeDataProvider(IConversation conversation) : base(conversation)
    {
    }

    #region IEmployeeDataProvider Members

    IList<Employee> IEmployeeDataProvider.GetAll()
    {
        return _repository.GetAll().List<Employee>();
    }

    IList<Employee> IEmployeeDataProvider.GetRange(int resultSet, int rangeSize)
    {
        return _repository.GetRange(resultSet, rangeSize).List<Employee>();
    }

    Employee IEmployeeDataProvider.Get(int employeeId)
    {
        return _repository.Get(employeeId);
    }

    void IEmployeeDataProvider.Save(Employee employee)
    {
        _repository.Save(employee);
    }

    IList<Territory> IEmployeeDataProvider.GetTerritories()
    {
        return _conversation.Session.CreateCriteria(typeof (Territory)).List<Territory>();
    }

    #endregion
}

In this class we have the delegation of the IRepository (sitting in the abstract base) and we also have direct access to the NHibernate Session so we can add further methods of any kind. This also allows us the flexibility if you’d rather the EmployeeDataProvider had GetEmpoyees() instead of GetAll() it would allow that easily.

Since the repository itself is not exposed at the provider level this allows us to return the actual results in anyway we want. It allows us to further modify the basic queries by adding NHibernate where clauses to the Criteria if we so choose. Since the actual ICriteria won’t be exposed outside of the data provider we don’t need to worry about client interactions causing database usage. This would also allow us if we added NHibernate LINQ to not be concerned with returning the Queryable results for the same reason.

This pattern would also work directly with LINQ2SQL / LINQ2Entities / DLINQ by changing where the NHibernate session is dealt with and using your entity provider. I feel this is a perfect to the data access patern as it protects the code from becoming too unweilding by basing all communication directly through the ICriteria and giving our data providers concrete result lists.

Let me know what you think!

kick it on DotNetKicks.com

Shout it

BloggingContext.ApplicationInstance.CompleteRequest();

Advertisements

Conversation Per Business Transaction using PostSharp and IoC

Earlier this month I encountered the notion of the Conversation per Business transaction paradigm for NHibernate session management as the overrall successor to the session per request pattern. With my exploration on this topic I found it quite confusing to implement in the only existing examples of it. Which is why I wrote a simple version for myself leveraging inversion of control and PostSharp.

Firstly,  everything drives off an IConversation:

public interface IConversation
{
    void Start();
    void Pause();
    void Resume();
    void End();
    void Abort();
    ISession Session { get; }
}

The conversation is a fairly simple idea, just as in a real life conversation you have a start to it, you can pause the conversation (which is how to commit the conversations), resume the conversation, end the conversation and abort the conversation. Imagine the scenario of a school class and students who have learning commited to their memory. A day could follow a similar context as this:

8:00 Class starts
Math is taught, Science is taught
12:00 Class is paused for recess (all information is committed)
13:00 Class is resumed
Creationism is taught, but realized to be made up and Class is aborted
14:00 Class is started again
More subjects are taught
15:00 Class is ended and all information flushed to students long term memory.

This example is fairly contrived but if you replace students with the database and act of class being taught with the conversation it should be pretty clear a flow that could occur over a single session for a conversation.

Next is the actual implementation of the Conversation class.

public class Conversation : IConversation, IDisposable
{
    private readonly INHibernateSessionManager _sessionManager;

    public ISession Session { private set; get; }

    [InjectionConstructor]
    public Conversation(INHibernateSessionManager sessionManager)
    {
        _sessionManager = sessionManager;
    }

    /// <summary>
    /// Starts this instance.
    /// </summary>
    public void Start()
    {
        if (Session != null && (Session.IsOpen || Session.IsConnected))
        {
            Abort();
        }
        Session = _sessionManager.GetSession(FlushMode.Never);
        Resume();
    }

    /// <summary>
    /// Pauses this instance.
    /// </summary>
    public void Pause()
    {
        Commit(Session);

    }

    /// <summary>
    /// Resumes this instance.
    /// </summary>
    public void Resume()
    {
        if (Session == null)
            Start();

        if (Session == null)
            throw new AccessViolationException("Session could not be created");

        if (!Session.IsConnected)
        {
            Session.Reconnect();
        }
        Session.BeginTransaction();
    }

    /// <summary>
    /// Ends this instance.
    /// </summary>
    public void End()
    {
        if (Session == null || !Session.IsOpen) return;

        FlushAndCommit(Session);
        Session.Close();
    }

    /// <summary>
    /// Aborts this instance.
    /// </summary>
    public void Abort()
    {
        if (Session == null || !Session.IsOpen) return;

        if (Session.Transaction != null && Session.Transaction.IsActive)
        {
            Session.Transaction.Rollback();
        }
        Session.Close();
    }

    /// <summary>
    /// Commits the specified session.
    /// </summary>
    /// <param name="session">The session.</param>
    private static void Commit(ISession session)
    {
        if (session.Transaction != null && session.Transaction.IsActive)
        {
            session.Transaction.Commit();
        }
    }

    /// <summary>
    /// Flushes the and commit.
    /// </summary>
    /// <param name="session">The session.</param>
    private static void FlushAndCommit(ISession session)
    {
        if (session.Transaction == null || !session.Transaction.IsActive) return;

        session.Flush();
        session.Transaction.Commit();
    }

    #region Implementation of IDisposable

    public void Dispose()
    {
        End();
    }

    #endregion
}

This class is a little bit long but nothing is that complex and I think every method is very straight forward. I’m going to skip over a few things that are not needed for understanding what this class does. The INHibernateSessionManager is an interface to a class that is a basically a wrapper to NHibernate’s ISessionFactory. For all intensive purposes this class could be ISessionFactory instead and the implementation wouldn’t change other than it would be session = Factory.OpenSession(); session.FlushMode = FlushMode.Never;

The InjectionConstructor attribute is a Microsoft Unity (Inversion of Control framework) specific convention that informs Unity to inject the NHibernate SessionFactory dependency into a Conversation anytime it is created. Unity will store a singleton copy of the SessionFactory for the life of the application.

Next up is the DataProvider class that will actually use the Conversation to talk to the database physically.

public class EmployeeDataProvider : IEmployeeDataProvider
{
    private readonly IConversation _conversation;

    [InjectionConstructor]
    public EmployeeDataProvider(IConversation conversation)
    {
        _conversation = conversation;
    }

    IList<Employee> IEmployeeDataProvider.GetEmployees()
    {
        return _conversation.Session.CreateCriteria(typeof (Employee)).List<Employee>();
    }
}

This is a very basic method that is used with NHiberate, it’s the syntax to get a list of objects from the database. I have some other methods in my provider but the code is less important now onto calling the provider.

[Test]
[BusinessConversation]
public void BusinessConversationTest()
{
    const int id = 9;
    var employee = _provider.GetEmployee(id);
    Assert.IsNotNull(employee);

    var employees = _provider.GetEmployees();
    Assert.IsTrue(employees.Count > 0);

    var territories = _provider.GetTerritories();
    Assert.IsTrue(territories.Count > 0);
}

In the setup call for this test Unity will resolve the _provider and assign it a Conversation which has the SessionFactory in it for opening the session. The same session is used for each of the calls to the database and committed as a single transaction when the method exits. This is done automagically by PostSharp.

PostSharp is an aspect orientated programming framework that allows you to create attributes can trigger methods before entering a method with the attribute and after exiting. The code for the BusinesConversation attribute is

[Serializable]
public sealed class BusinessConversation : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionEventArgs eventArgs)
    {
        var container = HttpContext.Current != null ?
            HttpContext.Current.Application.GetContainer() : UnityTestContainer.Instance;
        var conversation = container.Resolve<IConversation>();
        conversation.Resume();
    }

    public override void OnExit(MethodExecutionEventArgs eventArgs)
    {
        var container = HttpContext.Current != null ?
            HttpContext.Current.Application.GetContainer() : UnityTestContainer.Instance;
        var conversation = container.Resolve<IConversation>();
        conversation.Pause();
    }
}

Now this has some Unity specific code in it where it calls to the container to resolve the Conversation but the important part is that OnEntry to a method with the BusinessConversation attribute the conversation is resumed. This will either resume an existing conversation that’s stored in the session or it will create a new one. When it exits the method the conversation is paused which commits the transaction to the database.

The other code where it does resolution checking on HttpContext or reads from my UntityTestContainer does not really make me happy and eventually will be refactored to be cleaner in one way or another. But this code would be specific to how you interact with your container that would store the Conversations.

The only other issue I have with any of this is exposing the Session from the Conversation, I couldn’t figure out a simplier way for allowing my data providers to actually interact with the session to physically hit the database otherwise. I considered instead of a Conversation containing a session to actually make it implement ISession and assign it to itself during the creation but that didn’t sound right to me even more so.

I’d be grateful for any feedback on my implementation here: good, bad or indifferent. I feel I’ve finally put together a clean simple to understand post on how to correctly manage NHibernate’s session that doesn’t require implementing the UnitOfWork pattern and leverages dependency injection to keep the code seperated and decoupled as much as possible. The full source to my project as always can be found on my Assembla page.

kick it on DotNetKicks.com

Shout it

BloggingContext.ApplicationInstance.CompleteRequest();

Working with DataTables/Datarows

Sadly the project I am on at work is all circa 2005 standards where everything is DataTables and Data Adapters etc. These classes are an incredibly annoying “feature” to work with and are just brutal since it’s impossible to ever have a good domain design with them. But I wrote this class to make life easier to deal with them. It uses .net 3.5 extension methods but with a few minor changes it will run on .net 2.0. Some of the basis of this code for the ChangeType method came from QueryString Candy – Could Rot Your Teeth (dead) however I’ve added my own touches to it.

Here’s my extension method class:

///<summary>
/// Extension methods for manipulating DataRows
///</summary>
public static class DataRowUserExtensions
{
    /// <summary>
    /// Determines whether [is empty string] [the specified data row].
    /// </summary>
    /// <param name="dataRow">The data row.</param>
    /// <param name="key">The key.</param>
    /// <returns>
    ///   <c>true</c> if [is empty string] [the specified data row]; otherwise, including DBNull, <c>false</c>.
    /// </returns>
    public static bool IsEmptyString(this DataRow dataRow, string key)
    {
        if (dataRow.Table.Columns.Contains(key))
            return !dataRow.IsNull(key) && dataRow[key].ToString() == string.Empty;

        throw new ArgumentOutOfRangeException(key, dataRow, "does not contain column");
    }

    /// <summary>
    /// Determines whether the specified data row is null.
    /// </summary>
    /// <param name="dataRow">The data row.</param>
    /// <param name="key">The key.</param>
    /// <returns>
    ///   <c>true</c> if the specified data row is null; otherwise, <c>false</c>.
    /// </returns>
    public static bool IsNull(this DataRow dataRow, string key)
    {
        if (dataRow.Table.Columns.Contains(key))
            return dataRow[key] == null || dataRow[key] == DBNull.Value;

        throw new ArgumentOutOfRangeException(key, dataRow, "does not contain column");
    }

    /// <summary>
    /// Determines whether [is null or empty string] [the specified data row].
    /// </summary>
    /// <param name="dataRow">The data row.</param>
    /// <param name="key">The key.</param>
    /// <returns>
    ///   <c>true</c> if [is null or empty string] [the specified data row]; otherwise, <c>false</c>.
    /// </returns>
    public static bool IsNullOrEmptyString(this DataRow dataRow, string key)
    {
        if (dataRow.Table.Columns.Contains(key))
            return dataRow.IsNull(key) && dataRow.IsEmptyString(key);

        throw new ArgumentOutOfRangeException(key, dataRow, "does not contain column");
    }

    /// <summary>
    /// Gets the specified data row.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="dataRow">The data row.</param>
    /// <param name="key">The key.</param>
    /// <returns></returns>
    public static T Get<T>(this DataRow dataRow, string key)
    {
        if (dataRow.Table.Columns.Contains(key))
        {
            // If we're trying to convert an empty string to string return the string instead
            // default(string) which is null, otherwise return null if dataRow IsNullOrEmptyString
            // else convert
            return typeof (T) == typeof (string) && dataRow.IsEmptyString(key)
                ? (T) dataRow[key] : (dataRow.IsNullOrEmptyString(key)
                ? default(T) : (T) ChangeTypeTo<T>(dataRow[key]));
        }

        throw new ArgumentOutOfRangeException(key, dataRow, "does not contain column");
    }

    /// <summary>
    /// Changes the type to.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    private static object ChangeTypeTo<T>(this object value)
    {
        if (value == null)
            return null;

        Type underlyingType = typeof (T);
        if (underlyingType == null)
            throw new ArgumentNullException("value");

        if (underlyingType.IsGenericType && underlyingType.GetGenericTypeDefinition().Equals(typeof (Nullable<>)))
        {
            var converter = new NullableConverter(underlyingType);
            underlyingType = converter.UnderlyingType;
        }

        // Guid convert
        if (underlyingType == typeof (Guid))
        {
            return new Guid(value.ToString());
        }

        // Check for straight conversion or value.ToString conversion
        var objType = value.GetType();

        // If this is false, lets hope value.ToString can convert otherwise exception
        bool objTypeAssignable2typeT = underlyingType.IsAssignableFrom(objType);

        // Do conversion
        return objTypeAssignable2typeT ? Convert.ChangeType(value, underlyingType)
                                                        : Convert.ChangeType(value.ToString(), underlyingType);
    }
}

Usage example:

ds.Tables[0].Rows[0].Get<DateTime?>("SomeDate")

Basically what is going first it checks to make sure that “SomeDate” is an actual column inside the DataRow, then it checks to make sure dr[“SomeDate”] isn’t null, DBNull or an empty string.

Inside of the ChangeType method it will then resolve whether <T> is an object or a nullable object. If it’s a nullable object it will find the actual object type.

Next we do an outside check to see if it’s a Guid (since Convert.ChangeType can’t handle guids) and if it is to return the guid or it will bubble up an exception of underlyingType == typeof(Guid) and value is not a valid guid.

After that the actual conversion occurs first it checks if the type of value is Assignable To underlyingtype, if it is then it will do the Convert.ChangeType. If it’s not assignable we’re going to hope the string representation of value can be converted to type T otherwise it will fail. This second case is useful if you want to get the string representation of a number or date. As with the previous example:

ds.Tables[0].Rows[0].Get<string>("SomeDate")

Will return the string value of the SomeDate value instead of raising an exception if we didn’t have the second condition of the return statement there.

Hope this helps some of you out as much as it does me!

BloggingContext.ApplicationInstance.CompleteRequest();

Method to determine if data range contains a leap year

Update 1/14/2008: I pulled a Microsoft zune! My leap check was actually off by 1. Corrected algorithm

As I was going through some of code I previously worked on today I came across this method I wrote a while ago. I’m not too sure  if it will help anyone else but I figured I’d throw it up here. Basically I had a need to figure out if a date entered was inside a period of time in the future (in my case specifically 2.5 years and 3.0 years in the future). My original plan was to just check if number of days fit in between 365*2.5  and 365*3 but I realized as rare of a possiblity as it was a potential leap year could have foiled my plans.

So basically I wrote this method for me to be able to calculate if I need to add another day to my range to make sure they weren’t short changed a day because leap year occurred.

I’d love to hear your opinions on this code if there is anything you’d do differently.

/// <summary>
/// Determines if the DateRange contains a leap year.
/// </summary>
/// <param name="startDate">The start date.</param>
/// <param name="endDate">The end date.</param>
/// <returns></returns>
private static bool DateRangeContainsLeapYear(DateTime startDate, DateTime endDate)
{
  if (startDate.Year == endDate.Year)  
    return  DateTime.IsLeapYear(startDate.Year )

  if (startDate > endDate)
    throw new InvalidDataException("startDate must be less than or equal to endDate.");

  //Bounds check Feb will exist either in start of the first time span date
  //or at the end of the last date potentially
  if (startDate.Month < 3 && DateTime.IsLeapYear(startDate.Year))
    return true;
  if ((endDate.Month >= 3 || (endDate.Month == 2 && endDate.Day == 29))
&& DateTime.IsLeapYear(endDate.Year))
    return true;

  //Start year can't be leap year otherwise we're done
  int startYear = startDate.Year + 1;

//Upper bounds will be handled by i < endYear
  int endYear = endDate.Year;

  for (int year = startYear; year < endYear; year++)
  {
    if(!DateTime.IsLeapYear(year)) continue;
    return true;
  }

  return false;
}

Edit: After feedback from Arran Dyer the endDate.Month > 3 check should be endDate.Month >= 3. This prevents the edge case of comparing 2 march dates occurring inside a leap year from errantly returning false .

BloggingContext.ApplicationInstance.CompleteRequest();

Adding Inflector to UnityWeb

Today as I was browsing the Fluent NHibernate discussion boards I was reading the post regarding features that the creators of the S#arp Architecture were interested in seeing.

One of the things that was pointed out was that FH doesn’t include a pluralizer which can make convention mapping problem matic.

Take my current AutoPersistanceModel

var persistenceModel = AutoPersistenceModel.MapEntitiesFromAssemblyOf<Employee>()
.WithConvention(c => c.DefaultLazyLoad = false)
.WithConvention(convention =>   convention.GetTableName = type => type.Name + "s")
.WithConvention(convention => convention.GetPrimaryKeyNameFromType = type => type.Name + "ID")
.WithConvention(convention => convention.GetForeignKeyName = prop => prop.Name + "ID")
.WithConvention(convention=>convention.DefaultCache = cache => cache.AsReadWrite())
.WithConvention(c => c.OneToManyConvention = m =>
                                                 {
                                                     m.Cascade.All();
                                                     m.LazyLoad();
                                                 })
.ForTypesThatDeriveFrom<Category>(autoMap =>
                                      {
                                            autoMap.WithTable("Categories");
                                          autoMap.Map(p => p.Name, "CategoryName");
                                      })
.ForTypesThatDeriveFrom<Territory>(autoMap =>
                                       {
                                             autoMap.WithTable("Territories");
                                           autoMap.Map(p => p.Description, "TerritoryDescription");
                                           autoMap.Map(p => p.Region,
 "RegionID").CustomTypeIs(typeof (Region));
                                       })
;

In more than 1 senario I need to force the autoMap to use the correct spelling of a table name instead of just being able to append S on it. With Inflector I can get a much cleaner map and only to have:

var persistenceModel = AutoPersistenceModel.MapEntitiesFromAssemblyOf<Employee>()
.WithConvention(c => c.DefaultLazyLoad = false)
.WithConvention(convention =>   convention.GetTableName = type => Inflector.Pluralize(type.Name))
.WithConvention(convention => convention.GetPrimaryKeyNameFromType = type => type.Name + "ID")
.WithConvention(convention => convention.GetForeignKeyName = prop => prop.Name + "ID")
.WithConvention(convention=>convention.DefaultCache = cache => cache.AsReadWrite())
.WithConvention(c => c.OneToManyConvention = m =>
                                                 {
                                                     m.Cascade.All();
                                                     m.LazyLoad();
                                                 })
.ForTypesThatDeriveFrom<Category>(autoMap =>
                                      {
                                          autoMap.Map(p => p.Name, "CategoryName");
                                      })
.ForTypesThatDeriveFrom<Territory>(autoMap =>
                                       {
                                           autoMap.Map(p => p.Description, "TerritoryDescription");
                                           autoMap.Map(p => p.Region,
 "RegionID").CustomTypeIs(typeof (Region));
                                       })
;

You can download Inflector and it’s source over at Andrew Peter’s blog Inflector.NET.

On a further note I believe I’ve learned how to remove the need to have the specific mappings for my enum properties, Name property and Description property which will significantly reduce the code noise of the auto mapping which will show up soon in another blog bost.

Happy New Year Everyone

I hope everyone had a happy new year and had good holidays to close out last year. I’m still working on UnityWeb I think I finally am close to grasping the last stumbling block I’ve had with NHibernate the session management of it as I’ve just learned of the conversation per business transaction pattern.

Just something I ran across today that should give everyone a brief chuckle is this snippet of code:

if (param[1].Value.GetType() != Type.GetType("System.DBNull"))

Isn’t that just some of the most beautiful code you’ve ever seen?
/sarcasm

You can definitely file this under the Lexicon of Crap code.