I Am Not Myself


Implementing Oxide Data Provider with Linq to Fluent NHibernate

Someone linked the Oxide Channel 9 video yesterday either on Twitter or in IRC. I don’t quite remember who. I was intrigued  after watching the video and have been wanting a good excuse to seriously play around with ASP.NET MVC. I have been wanting to hop blog engines from dasBlog for a while now and Oxide appears to have all the features I use. So I downloaded the bits and started looking around.

Oxide is a fairly straight forward blog engine built on MVC. All the standard features are there including RSS, Trackbacks, Comments and Windows Live Writer support via MetaWebLog API. Oxide also uses a provider model for most of its major functionality, so building alternatives is pretty easy as well.

By default the data access layer is build on Linq To Sql, which I found an interesting choice considering the recent death bells tolled for it. In order to make the data provider generic and swapable, the Oxide team chose to create interfaces for their entities.

In the main Oxide.Data namespace are a series of interfaces that look like this:

public interface IArea
        Guid SiteID { get; set; }
        Guid ID { get; set; }
        string Name { get; set; }
        string DisplayName { get; set; }
        string Description { get; set; }
        string Type { get; set; }
        string TypeUrl { get; set; }
        DateTime? Created { get; set; }
        DateTime? Modified { get; set; }

The Linq to Sql entities are created using a typical DBML file. Partial classes are then created for each entity and they are set to inherit from the interface:

partial class oxite_Area : IArea
        public Guid ID
            get { return AreaID; }
            set { AreaID = value; }


This design allow the rest of the application to only deal with the interface leaving the persistence concerns hidden and isolated in the data provider class. This seemed really clean to me, so I wanted to take a stab at implementing a data provider using my favorite ORM technology.

So I fired up a new project and imported NHibernate, Fluent NHibernate and Linq to NHibernate and started hacking out some code. The main entry point to the data provider is the IOxideDataProvider interface. This interface exposes a series of repository interfaces:

public interface IOxiteDataProvider
        IAreaRepository AreaRepository { get; }
        IBackgroundServiceActionRepository BackgroundServiceActionRepository { get; }
        ILanguageRepository LanguageRepository { get; }
        IMembershipRepository MembershipRepository { get; }
        IMessageRepository MessageRepository { get; }
        IPostRepository PostRepository { get; }
        IResourceRepository ResourceRepository { get; }
        ITagRepository TagRepository { get; }
        ITrackbackRepository TrackbackRepository { get; }

I started by implementing stubs for this interface. I wired my new assembly into the Oxide web.config as the data provider and fired up the site. I wanted to see what was the first repository it would attempt to use. I quickly got a lemon meringue screen crying about AreaRepository.

AreaRepository deals with the IArea entity interface. The Oxide data provider defines this entity partially in DBML and an added partial class. I needed my own implementation of it. This is where the entity interfaces come in handy.

public class Area : AuditedEntity, IArea
        private string description;
        private string displayName;

        private string name;
        private Guid siteId;
        private string type;
        private string typeUrl;

        public string Name
            get { return name; }
            set { name = value; }



Here Area is a simple POCO object that implements IArea. I also pushed up some common properties into a base class set of EntityBase which provides identity via a GUID and a AuditedEntity which provides created and modified date tracking.

Looking through the various repository code, it looked to me like the Oxide team had created  one to one repositories like this to get around limitations of Linq to Sql. I decided to try to create a generic repository to handle all entity types’ simple CRUD operations. So I created a typical IRepository interface like so:

internal interface IRepository
        IQueryable GetList();
        T GetById(long id);
        void Save(T entity);
        void Delete(T entity);
        T GetOne(SpecificationBase query);
        IQueryable GetList(SpecificationBase query);
 internal interface IPagedRepository
        IQueryable GetPagedList(SpecificationBase query, int pageSize, int pageId);

This interface defines very basic Create, Read, Update and Delete functionality for a repository. The Specification stuff is a really cool idea that I blatantly ripped off from RossCode. Check out his article on how that works. It is irrelevant to the topic at hand, so I wont go into it now. I may not even need to use it by the time I am done. I also threw in a interface for paging just in case.

Implementing these interfaces are pretty straight forward and once again this is most likely not my code but something borrowed from somewhere else.

public class Repository
        : IRepository, IPagedRepository
        public Repository(ISession _session)
            this.session = session;

        private ISession session { get; set; }

        public IQueryable GetPagedList(SpecificationBase query,
                                          int pageSize, int pageId)
            if (pageId == 0) pageId = 1;
            return GetList(query).Take(pageSize).Skip(pageId*pageSize);

        public IQueryable GetList()
            return (from entity in _session.Linq() select entity);

        public T GetById(long id)
            return _session.Get(id);

        public void Save(T entity)

        public void Delete(T entity)

                public T GetOne(SpecificationBase query)
            return query.SatisfyingElementFrom(_session.Linq());

                public IQueryable GetList(SpecificationBase query)
            return query.SatisfyingElementsFrom(_session.Linq());


I can now use my generic repository for all simple CRUD operations required by the interface required repositories. I won’t show a full implementation but the basics of it look like this:

public class AreaRepository : IAreaRepository
        private readonly IRepository&lt;Area&gt;<area shape="RECT" coords="0,0,0,0" /> repository;

        public AreaRepository(ISession session)
            repository = new Repository&lt;Area&gt;<area shape="RECT" coords="0,0,0,0" />(session);

        private IQueryable&lt;Area&gt;<area shape="RECT" coords="0,0,0,0" /> getAreas(Guid siteID)
            return from a in repository.GetList()
                   where a.SiteID == siteID
                   select a;
            // orderby a.AreaName



As you can see the area repository implements IAreaRepository which satisfies the IOxideDataProvider interface. Implementing the rest of the class was pretty much a cut & paste job on the Oxide code to get the linq queries all the methods are based on.

One problem I did run into was that the version of Linq to NHibernate I am using does not appear to support orderby. This might not be the case with the actual trunk version, but the one that is in the Flient NHibernate trunk doesn’t. I simply commented the item out for now and will return to it later.

I am currently passing in the NHibernate session and newing up an instance of the generic repository. This isn’t the cleanest design but I can push the repository creation up when I get to introducing my IoC container of choice Ninject. I am not quite sure how I am going to do that in Oxide, so I am leaving it for another day.

I now have an end to end solution for the Area entity. All that is left is persistence concerns. I need to create a NHibernate mapping for the Area class to my database. Fluent NHibernate makes this incredibly simple.

public class AreaMap : ClassMap<area shape="RECT" coords="0,0,0,0" />
        public AreaMap()
            Id(x =&gt; x.ID,"AreaID").GeneratedBy.Guid().WithUnsavedValue(null);
            Map(x =&gt; x.Name).TheColumnNameIs("AreaName").WithLengthOf(256).CanNotBeNull();
            Map(x =&gt; x.DisplayName).WithLengthOf(256).CanNotBeNull();
            Map(x =&gt; x.Description).WithLengthOf(256).CanNotBeNull();
            Map(x =&gt; x.Type).WithLengthOf(25).CanNotBeNull();
            Map(x =&gt; x.TypeUrl).WithLengthOf(25).CanNotBeNull();
            Map(x =&gt; x.Created).TheColumnNameIs("CreatedDate").CanNotBeNull();
            Map(x =&gt; x.Modified).TheColumnNameIs("ModifiedDate").CanNotBeNull();

I can even verify this is right in unit tests by using the very awesome PersistenceSpecification class provided by Fluent NHibernate.

        public void Can_Add_Area_To_Database()
            var testDate = new DateTime(2008, 12, 1);
            new PersistenceSpecification<area shape="RECT" coords="0,0,0,0" />(Session)
                .CheckProperty(x =&gt; x.Name, "Name")
                .CheckProperty(x =&gt; x.DisplayName, "DisplayName")
                .CheckProperty(x =&gt; x.Description, "Description")
                .CheckProperty(x =&gt; x.TypeUrl, "TypeUrl")
                .CheckProperty(x =&gt; x.Type, "Type")
                .CheckProperty(x =&gt; x.Created, testDate)
                .CheckProperty(x =&gt; x.Modified, testDate)

Now that is hot. James and the gang have done amazing things with Fluent NHibernate. Next up, I plan to map all the entities in my project in an effort to understand the domain model a bit more and flesh out some unit tests around what I have written.

I have not released the source code for this post yet, as I want to get a working Oxide Data Provider first that way people can actually see it working. So look for more posts on this as I work my way though it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: