The S#arp framework: understanding the data assembly
After a small detour into the NH Validator framework (and yes, it was really a small detour since we didn’t see how it integrates really well with NH and other frameworks nor how we can create custom validation rules), in this post we’re going back to our study of the S#arp framework. Today, we’re going to take a deep dive into some of the helper classes that are baked into the SharpArch.Data assembly.
We’ll start by looking at the Repository.cs file. This file contains two classes: RepositoryWithTypedId<T, IdT> and Repository<T>. Repository extends RepositoryWithTypedId, specifying IdT as int. As you might expect, RepositoryWithTypedId contains the code that implements IRepositoryWithTypedId interface.
The RepositoryWithTypedId adds a new property to the API implemented from the interface: the Session property. This (read only) property returns a reference to the ISession instance that the remaining methods use to perform their work. The implementation of this property is really simple: it just delegates to the static NHibernateSession.Current property, which is responsible for doing all the work and getting a valid reference to the “current” ISession (we’ll come back to this class in the future).
Once we get a reference to a valid ISession instance (which, as we’ve seen, relies on the NHibernateSession class), implementing the interface methods are fairly simple . The only note I’d like to make here is that the FindOne method will throw (NotUniqueResultException) if it gets more than one hit.
Now let’s proceed and take a look into the (way more interesting) NHibernateSession class. This is a static class which encapsulates everything you need in order to:
- load the object/table mappings and build a Configuration object (you can do this through the traditional XML files or by using a fluent interface approach)
- register eventual interceptors (though you probably shouldn’t go this way because listeners are the way to go with NH 2);
- get a valid ISession instance from a ISessionFactory previously obtained.
In practice, you’re supposed to initialize the NHibernateSession by calling one of the overloads of the Init method (which you should only once,at startup). Then,you can get a valid session by invoking the Current property:
public static ISession Current {
get {
ISession session = Storage.Session;
if (session == null) {
if (RegisteredInterceptor != null) {
session = SessionFactory.OpenSession(RegisteredInterceptor);
}
else {
session = SessionFactory.OpenSession();
}
Storage.Session = session;
}
return session;
}
}
As you can see, the class relies on some sort of storage for keeping the created session (notice the use of the Storage static field). Before creating a new ISession instance, the class will always check for a valid instance of that type in that static field. If it finds one, then it will simply reuse it as the “current” ISession instance. This storage is represented by the ISessionStorage interface:
public interface ISessionStorage {
ISession Session { get; set; }
}
As we’ll see in the future, the S#arp framework introduces one implementation of this interface that lets you use the session-per-request pattern.
The NHibernateRepositoryWithTypedId and NHibernateRepository generic classes expand the previous repository classes and give you much more control over the ISession usage. Before ending, there’s still time to talk about the DbContext class. This class implements the IDbContext interface and relies on the NHibernateSession in order to get a valid ISession instance.
There’s still one important class to cover (EntityDuplicateChecker), but I’ll leave it for another day!