Saturday, April 16, 2011

Implementing A Common Interface For NHibernate And RavenDb LINQ Providers

Background Knowledge

This is for those who are not familiar with the concept of a query provider. It's all about IQueryable<T>. By implementing this interface, you promise that you have a class (a query provider) that knows how to populate you (typically a collection) based on some domain specific data store. It can be a document database, a relational database, or even XML. In the case of Raven and NHibernate, we're dealing with document and relational databases. Raven's domain specific language is HTTP and REST, while NHibernate's is an abstraction layer atop SQL. The heart of any LINQ provider is expression trees. We call them quotations in F#, and they can be a nightmare for you when you want to use an existing LINQ implementation. Shame on you fsc. The c sharp compiler, csc, is a lot more friendly and compliant about emitting expression trees.

That being said, expression trees are where the magic happens. They are merely runtime representations of our code. The compiler will convert our calls against IQueryable like Where and Select to expression trees at compile time as opposed to delegates. Then it's up to you to implement an expression tree visitor and LINQ provider that knows how to parse each kind of expression supported by your API. You can find NHibernate's here and Raven's here. You'll be working with runtime representations of the standard LINQ query operators like Select, Where, OrderBy, and GroupBy. I'd like to assume everyone knows that there is a difference between IQueryable<T> and IEnumerable<T>, but I highly doubt that. What can be confusing for some is when they call


var five = new List<int> {3, 4, 5}.Where(n => n % 5 == 0).Single();

and it works. That's LINQ to Objects. In that instance, we're working with IEnumerable<T>. The key thing to remember is that both IQueryable<T> and IEnumerable<T> both have a set of extension methods that target them, and depending on which one you use you'll either love or hate the results. The extensions for IEnumerable<T> work with in memory collections as opposed to LINQ providers and expression trees. The extensions for IQueryable<T> are just an abstraction layer sitting atop your LINQ provider. You implement the LINQ provider, and .NET will invoke it at the proper time passing in the proper arguments (an expression tree). All you have to do is parse the tree and emit your domain specific output. Then you send that output to whatever backend you're encapsulating, fetch the results, and send them back to the client. I won't go any further into LINQ providers, but I figured I could clear up a little smoke by providing some concrete examples. The last thing I'll add is that IQueryable<T> is always lazily executed (just like IEnumerable<T>) and inherits from IEnumerable<T>. All IEnumerable<T> means is that you can iterate (for each) over its results. Now it's not that simple because the compiler generates this hidden class and  a state machine but we won't get into that and monads. What makes it lazy is that your query won't be executed until the client tries to actually iterate. This is cool because it allows us to continually make calls on our IQueryable<T> without it hitting our data store each time. Obviously we're not ready to consume any results until we start to iterate so everything is deferred up until that point. And don't worry about the compiler accidentally choosing the wrong call to Where or Select. It's smart enough to know that IQueryable<T> is more specific that IEnumerable<T> and invoke the right set of extensions.

I'd also like to conclude with a low level deep dive into LINQ.

Implementing the UoW

Let's get started shall we. First thing's first; we need a common interface to wrap the NHibernate and Raven sessions respectively.


public interface ISession : IDisposable {
    IQueryable<TEntity> Query<TEntity>() where TEntity : Entity;
    void Add<TEntity>(TEntity entity) where TEntity : Entity;
    void Update<TEntity>(TEntity entity) where TEntity : Entity;
    void Delete<TEntity>(TEntity entity) where TEntity : Entity;
    void SaveChanges();

    #region Future Load Methods. Can't use now because Raven forces Id's to be strings. If were not for that, we could make this generic between NHibernate and RavenDb.

    // TEntity Load<TEntity, TId>(TId id) where TEntity : Entity<TId>;
    // IEnumerable<TEntity> Load<TEntity, TId>(IEnumerable<TId> ids) where TEntity : Entity<TId>;

    #endregion
}

As you can see, we make each session promise to give us an IQueryable<T>. We're also enforcing our sessions to implement Unit Of Work, hence the SaveChanges method. The rest of the functions are CRUD based. Lastly we need to be able to shut the session down and free up resources so we make all sessions implement IDisposable.

Now we'll make the concrete RavenSession and it's wrapper class UnitOfWork

public static class UnitOfWork {
    public static void Start() {
        CurrentSession = new RavenSession();
    }

    public static ISession CurrentSession {
        get { return Get.Current<ISession>(); }
        private set { Set.Current(value); }
    }
}

internal class RavenSession : ISession {
    readonly DocumentStore _documentStore;
    readonly IDocumentSession _documentSession;

    internal RavenSession() {
        _documentStore = new DocumentStore { Url = "http://localhost:8080" };
        _documentSession = _documentStore.Initialize().OpenSession();
    }

    public IQueryable<TEntity> Query<TEntity>() where TEntity : Entity {
        /* may need to take indexing into consideration. raven will generat temps for us, but that may not be so efficient. 
         * i don't even know how long the temps stick around for. Raven will try and optimize for us best it can. */
        return _documentSession.Query<TEntity>();
    }

    public void Add<TEntity>(TEntity entity) where TEntity : Entity {
        _documentSession.Store(entity);
    }

    public void Update<TEntity>(TEntity entity) where TEntity : Entity {
        _documentSession.Store(entity);
    }

    public void Delete<TEntity>(TEntity entity) where TEntity : Entity {
        _documentSession.Delete(entity);
    }

    public void SaveChanges() {
        _documentSession.SaveChanges();
    }

    public void Dispose() {
        _documentStore.Dispose();
        _documentSession.Dispose();
    }

    #region Future Load Methods. Can't use now because Raven forces Id's to be strings. If were not for that, we could make this generic between nHibernate and RavenDb.

    public TEntity Load<TEntity, TId>(TId id) where TEntity : Entity<TId> {
        throw new NotImplementedException();
    }

    public IEnumerable<TEntity> Load<TEntity, TId>(IEnumerable<TId> ids) where TEntity : Entity<TId> {
        throw new NotImplementedException();
    }

    #endregion
}

I hard coded the url for now, but obviously I'd want it to be read from configuration somewhere.

Next I need a class to store the current session. I took an idea from a buddy of mine and made it strongly typed and reusable. It's just a wrapper around HttpContext that falls back to an in memory dictionary for unit testing purposes.

public static class Ensure {
    public static void That(bool condition) {
        if(!condition)
            throw new Exception("an expected condition was not met.");
    }

    public static void That<TType>(bool condition, string message) where TType : Exception {
        if(!condition)
            throw (TType)Activator.CreateInstance(typeof (TType), message);
    }
}

public static class Get {
    public static T Current<T>() where T : class {
        var context = HttpContext.Current;
        var key = typeof(T).FullName;

        var value = context == null ? (T)Set.InMemoryValuesForUnitTesting[key] : (T)context.Items[key];

        Ensure.That(value != null);

        return value;
    }
}

public static class Set {
    internal static Dictionary<string, object> InMemoryValuesForUnitTesting = new Dictionary<string, object>();

   public static void Current<T>(T value) {
       var context = HttpContext.Current;
       var key = typeof(T).FullName;

       if (context == null)
           InMemoryValuesForUnitTesting[key] = value;
       else
           context.Items[key] = value;
    }
}

Implementing Core Domain Objects

It's nice to have a base structure in place from which our domain objects can derive. More specifically a base entity and repository class. The base repository is strongly typed and knows how to persist a specific type of entity. I created a Raven specific repository because all ids in Raven are strings (or so I thought. Raven actually supports POID generators just like NHibernate). That's just the default implementation. It was implemented that way so the ids could be RESTful and human readable. Who wants to see a GUID on the query string? Not I...

public class Entity {}

public class Entity<TId> : Entity {
    public TId Id { get; set; }
}

public class BaseRepository<T, TId> : IRepository<T, TId> where T : Entity<TId> {
    public void Add(T entity) {
        UnitOfWork.CurrentSession.Add(entity);
    }

    public IQueryable<T> All() {
        return UnitOfWork.CurrentSession.Query<T>();
    }

    public virtual T Get(TId id) {
        return All().Where(e => e.Id.Equals(id)).SingleOrDefault();
    }

    public IEnumerable<T> Get(IEnumerable<TId> ids) {
        var idList = ids.ToList();

        return All().Where(e => idList.Contains(e.Id));
    }

    public void Delete(T entity) {
        UnitOfWork.CurrentSession.Delete(entity);
    }

    public void Update(T entity) {
        UnitOfWork.CurrentSession.Update(entity);
    }
}

public interface IRepository<T, in TId> : ICreate<T>, IRead<T, TId>, IDelete<T>, IUpdate<T> where  T : Entity<TId> {}

public interface IDelete<in T> {
    void Delete(T entity);
}

public interface IRead<out T, in TId> where T : Entity<TId> {
    IQueryable<T> All();
    T Get(TId id);
    IEnumerable<T> Get(IEnumerable<TId> ids);
}

public interface ICreate<in T> {
    void Add(T entity);
}

public interface IUpdate<in T> {
    void Update(T entity);
}

internal class Person : Entity<string> {
    public string Name { get; set; }
    public int Age { get; set; }
}

internal class PersonRepository : BaseRepository<Person, string>, IPersonRepository {
}

internal interface IPersonRepository : IRepository<Person, string> {
}

I implemented CRUD interfaces for my repositories so that a client can choose which operations it wants to interact with. If all a client needs to do is perform reads, then it can consume the IRead<T> interface and opposed to a full fledged IRepository<T>. That concrete implementation of IRead<T> would still be able to inherit from BaseRepository<T>, but would not be consumed as such. Using dependency injection, you'd do something like...

Map<IRead<User>>.To<UserRepository>();

Then an MVC controller or some dependant object would look like...

public class AccountController(IRead<User> userRepository) {...}

This concept is the I in SOLID for Interface Segregation. Give the client only what it needs. Nothing more and nothing less.

I didn't think I'd need something for updates like IUpdate<T> since most UoW implementations will implement change tracking. For instance if you retrieve and entity from a Raven or NHibernate session and modify it, the changes will automatically be applied upon saving the session. But thent I thought about what happens in ASP.NET MVC when we handle updates. Say the user goes to our update page and makes some changes to some text fields that represent and entity. The ASP.NET MVC will automatically construct an instance of our entity or view model and allow us to persist it. Their is a TryUpdateModel that MVC exposes on controllers, but what if you're mapping from view model to entity/DTO? There'd be no need to retrieve the entity from the domain layer since you already have a copy of it in memory. I could be wrong on this. Maybe it's common practice to always find your entity, apply the necessary changes, and persist it. I'm not sure how most do it, but having IUpdate<T> doesn't hurt right?

Implementing a Request Module for ASP.NET

Now I need a request module that knows how to initialize the session and spawn the UoW.

public class UnitOfWorkModule : IHttpModule {
    public void Init(HttpApplication application) {
        application.BeginRequest += ApplicationBeginRequest;
        application.EndRequest += ApplicationEndRequest;
    }
 
    static void ApplicationBeginRequest(object sender, EventArgs e) {
        UnitOfWork.Start();
    }

    static void ApplicationEndRequest(object sender, EventArgs e) {
        UnitOfWork.CurrentSession.SaveChanges();
    }

    public void Dispose() {
        UnitOfWork.CurrentSession.Dispose();
    }
}

Let me add that I borrowed the idea of this particular implementation of UoW from a blog on nhforge.com. I tweaked it to my liking. It's not perfect, but I'm content with it and it works for me. I'd never go so far as to deem this the ultimate implementation of UoW.

The cool thing about our implementation is that we can switch from Raven to NHibernate with one line of code.

The bad thing is that we can't leverage any framwork specific goodies. For instance, the power behind document databases is that they perform lightning fast reads. This is accomplished via indexes. In Raven, we specifiy our indexes upon executing our queries, but there's no way for my BaseRepository to do that unless it knows it's dealing with Raven in particular. I'd have to cheat to do that and probably break my encapsulation by assuming certain things about the current ISession at hand. Something like type casting it to an IDocumentSession (Raven specific). Raven is smart enough to dynamically create indexes for us on the fly if it detects that we didn't specify one client side, and will eventually promote them to permanent indexes if we used them enough over a certain amount of time. Frankly you just need to be aware of what you're gaining and losing. You should analyze if the benefits of a clean and reusable design are worth the extra work it takes to be able to leverage all of your target frameworks features. Sometimes you can get away with declarative xml configuration independent of code, or decorating your classes with a specific attribute and having the runtime pick up on it; But that's a big maybe and a long shot in most cases. Regardless I thought this would be a cool idea and fun to implement.

Implementing Unit Tests For Raven

We're not done yet my friends. It's time for some unit tests. NUnit where you be?

[Test]
public void Person_Repository_Can_Save_Person() {
    IPersonRepository personRepository = new PersonRepository();

    var adubb = new Person { Age = 22, Name = "Antwan \"A-Dubb\" Wimberly \r\nIt's Okay To Not Hire A Senior Developer!! There Are Good Young Develpers Out There Too!!" };

    personRepository.Add(adubb);

    var id = adubb.Id;

    var adubbFromRepo = personRepository.Get(id);

    Assert.IsNotNull(adubbFromRepo);
    Assert.AreEqual(adubb.Id, adubbFromRepo.Id);
    Assert.AreEqual(adubb.Name, adubbFromRepo.Name);
    Assert.AreEqual(adubb.Age, adubbFromRepo.Age);

    personRepository.Delete(adubbFromRepo);

    UnitOfWork.CurrentSession.SaveChanges();
}


















Whoops!! Looks like Raven doesn't allow us to call Equals to in the body of our lamdas. Time to refactor. We need to override our base implementation of Get(TId id); Let's make it virtual and override it.

public class RavenBaseRepository<T> : BaseRepository<T, string> where T : Entity<string> {
    public override T Get(string id) {
        return All().Where(e => e.Id == id).SingleOrDefault();
    }
}

internal class PersonRepository : RavenBaseRepository<Person>, IPersonRepository {
}

I'm already noticing that my query is taking a rather long time to execute. This probably means Raven isn't making optimized reads. I'd expect things to execute a lot faster.

Anyway, let's run our test again.


















That's strange. We didn't find any results. Something must be going wrong with my Id. The problem is the entity is still transient. That is to say, it hasn't been persisted yet. We need to submit our changes before performing our read. Let's refactor our test.

personRepository.Add(adubb);

UnitOfWork.CurrentSession.SaveChanges();

var id = adubb.Id;

We told Raven to persist the object before retrieving it. Let's try again.

Ok. I'm still getting an error. I probably shouldn't be messing around with my Id property. That's Raven's. Let's make one final change.

var adubb = new Person { Age = 22, Name = "Antwan \"A-Dubb\" Wimberly \r\nIt's Okay To Not Hire A Senior Developer!! There Are Good Young Develpers Out There Too!!" };

Aaaaand!! Nope. Still didn't work. You may have caught on now but if you haven't the problem is inheritance. Raven apparently can't pick up on the fact that I'm inheriting my Id from my parent class Entity. So now I have to redefine it in the person class like so.

public class Person : Entity<string> {
    public new string Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

Alright. Things are working now according to my unit test and Raven Studio. My Add test passes. Now it's time to test delete.


[Test]
public void Person_Repository_Can_Delete_Person() {
    IPersonRepository personRepository = new PersonRepository();

    var adubb = new Person { Age = 22, Name = "Antwan \"A-Dubb\" Wimberly \r\nIt's Okay To Not Hire A Senior Developer!! There Are Good Young Develpers Out There Too!!" };

    personRepository.Add(adubb);

    UnitOfWork.CurrentSession.SaveChanges();

    var id = adubb.Id;

    var adubbFromRepo = personRepository.Get(id);

    Assert.IsNotNull(adubbFromRepo);

    personRepository.Delete(adubbFromRepo);

    UnitOfWork.CurrentSession.SaveChanges();

    adubbFromRepo = personRepository.Get(id);

    Assert.IsNull(adubbFromRepo);
}

This one worked right out of the box. No magic needed. Get is next.

[Test]
public void Person_Repository_Can_Get_Person() {
    IPersonRepository personRepository = new PersonRepository();

    var adubb = new Person { Age = 22, Name = "Antwan \"A-Dubb\" Wimberly \r\nIt's Okay To Not Hire A Senior Developer!! There Are Good Young Develpers Out There Too!!" };

    personRepository.Add(adubb);

    UnitOfWork.CurrentSession.SaveChanges();

    var id = adubb.Id;

    var adubbFromRepo = personRepository.Get(id);

    Assert.IsNotNull(adubbFromRepo);

    personRepository.Delete(adubb);
}

And lastly update. This one is pretty easy to test because of change tracking so I have 2 implementations. The first works just fine.

[Test]
public void Person_Repository_Can_Update_Person_Without_Calling_Update() {
    IPersonRepository personRepository = new PersonRepository();

    var adubb = new Person { Age = 22, Name = "Antwan \"A-Dubb\" Wimberly \r\nIt's Okay To Not Hire A Senior Developer!! There Are Good Young Develpers Out There Too!!" };

    personRepository.Add(adubb);

    UnitOfWork.CurrentSession.SaveChanges();

    var id = adubb.Id;

    var adubbFromRepo = personRepository.Get(id);

    Assert.IsNotNull(adubbFromRepo);

    const string changedName = "Changed Name";

    adubbFromRepo.Name = changedName;

    UnitOfWork.CurrentSession.SaveChanges();

    adubbFromRepo = personRepository.Get(id);

    Assert.AreEqual(changedName, adubbFromRepo.Name);

    personRepository.Delete(adubb);
}

But we run into problems with the second.





















Looks like Raven is forcing me to fetch my entity from the session before I can update it. It knows the entity is unattached. So I guess I could remove my implementation of Update. NHibernate however will properly convert my Contains call to an IN Clause; which is what I expect.

[Test]
public void Person_Repository_Can_Update_Person_When_Calling_Update() {
    IPersonRepository personRepository = new PersonRepository();

    var adubb = new Person { Age = 22, Name = "Antwan \"A-Dubb\" Wimberly \r\nIt's Okay To Not Hire A Senior Developer!! There Are Good Young Develpers Out There Too!!" };

    personRepository.Add(adubb);

    UnitOfWork.CurrentSession.SaveChanges();

    const string changedName = "Changed Name";
    const int changedAge = 19;

    var id = adubb.Id;

    // this entity didn't come from the session and thus is not being tracked. we're pretending like we've just
    // populated this entity in our controller based on the view and are about to persist it.
    var adubbFromRepo = new Person {Id = id, Age = changedAge, Name = changedName };

    personRepository.Update(adubbFromRepo);

    UnitOfWork.CurrentSession.SaveChanges();

    adubbFromRepo = personRepository.Get(id);

    Assert.AreEqual(changedName, adubbFromRepo.Name);
    Assert.AreEqual(changedAge, adubbFromRepo.Age);

    personRepository.Delete(adubb);
}

My last test if for Get with an overload. Of course it failed because Raven won't let me call Contains during my query. I'll figure it out later though. It's 1am right now and I'm beat. Plus my hot pocket is almost done cooking.

public static class ObjectExtensions {
    public static IEnumerable<TType> ToSingleEnumerable<TType>(this TType target) {
        yield return target;
    }
}

[Test]
public void Person_Repository_Can_Find_All_By_Id() {
    IPersonRepository personRepository = new PersonRepository();

    var adubb = new Person { Age = 22, Name = "Antwan \"A-Dubb\" Wimberly \r\nIt's Okay To Not Hire A Senior Developer!! There Are Good Young Develpers Out There Too!!" };

    personRepository.Add(adubb);

    UnitOfWork.CurrentSession.SaveChanges();

    var id = adubb.Id;

    var adubbFromRepo = personRepository.Get(id.ToSingleEnumerable()).FirstOrDefault();

    Assert.IsNotNull(adubbFromRepo);
    Assert.AreEqual(adubb.Id, adubbFromRepo.Id);
    Assert.AreEqual(adubb.Name, adubbFromRepo.Name);
    Assert.AreEqual(adubb.Age, adubbFromRepo.Age);

    personRepository.Delete(adubbFromRepo);
}

Implementing NHibernate Support

We're going to make a context switch to NHibernate now. We'll start with a concreate implementation of the ISession interface for NHibernate.

internal class NHibernateSession : ISession {
    static readonly ISessionFactory SessionFactory;

    static NHibernateSession() {
        // an expensive operation that should be called only once throughout the lifetime of the application. you'll typically see this in Application_Start of Global.asax.
        SessionFactory = Fluently
                            .Configure()
                            .Database(MsSqlConfiguration.MsSql2008
                                          .ConnectionString("Server=.; Database=NHPrac; Integrated Security=true;")
                                          .ShowSql())
                            .ExposeConfiguration(x => {
                                                     // for our CurrentSessionContext. this has to be configured or NHibernate won't be happy
                                                     x.SetProperty("current_session_context_class", "thread_static");
                                                         
                                                     // so the Product table can be exported to the database and be created before we make our inserts
                                                     var schemaExport = new SchemaExport(x);
                                                     schemaExport.Create(false, true);
                                                 })
                            .Mappings(x => x.FluentMappings.AddFromAssembly(Assembly.Load("Intell.Tests")))
                            .BuildSessionFactory();
        }

    internal NHibernateSession() {
        // sessions are really cheap to initialize/open
        var session = SessionFactory.OpenSession();

        session.BeginTransaction();

        CurrentSessionContext.Bind(session);
    }

    static NHibernate.ISession CurrentSession { get { return SessionFactory.GetCurrentSession(); } }

    public void Dispose() {
        // unbind the factory and dispose the current session that it returns
        CurrentSessionContext.Unbind(SessionFactory).Dispose();
    }

    public IQueryable<TEntity> Query<TEntity>() where TEntity : Entity {
        return CurrentSession.Query<TEntity>();
    }

    public void Add<TEntity>(TEntity entity) where TEntity : Entity {
        CurrentSession.Save(entity);
    }

    public void Update<TEntity>(TEntity entity) where TEntity : Entity {
        CurrentSession.Update(entity);
    }

    public void Delete<TEntity>(TEntity entity) where TEntity : Entity {
        CurrentSession.Delete(entity);
    }

    public void SaveChanges() {
        var transaction = CurrentSession.Transaction;

        if (transaction != null && transaction.IsActive)
            CurrentSession.Transaction.Commit();
    }
}

There's nothing special going on here. Just your standard Fluent NHibernate stuff and NHibernate basics in general. If my usage of the CurrentSessionContext class is unfamiliar to you then I'd suggest you get yourself a copy of the NHibernate 3.0 Cookbook. It's got the latest NHibernate best practices in it and was the basis of how I managed my NHibernate session.

Before I go any further I want to note that NHibernate won't let me call Equals in my Get(TId id) method so again I have to make a framework specific repository. Dangit!!

And yes I'm aware that S#arp Architecture has a base NHibernate and a base Entity class (I think...), but I wanted to take a stab at creating my own. It probably looks identical to what's already out there but oh well.

// we'd probably have to make a separate one for id's of type int to support identity columns
public class NHibernateBaseRepository<T> : BaseRepository<T, Guid> where T : Entity<Guid> {
    public override T Get(Guid id) {
        return All().Where(e => e.Id == id).SingleOrDefault();
    }
}

Next we'll build a ProductRepository, mapping file, and Product entity.

public class Product : Entity<Guid> {
    public virtual string Name { get; set; }
    public virtual int InventoryCount { get; set; }
}

public sealed class ProductMap : ClassMap<Product> {
    public ProductMap() {
        Id(x => x.Id)
            .GeneratedBy
            .GuidComb();
        Map(x => x.InventoryCount);
        Map(x => x.Name);
    }
}

internal class ProductRepository : NHibernateBaseRepository<Product>, IProductRepository {}

internal interface IProductRepository : IRepository<Product, Guid> {}

The Enity<TId> class becomes...

public class Entity<TId> : Entity {
    public virtual TId Id { get; set; }
}

Of course everything has to be virtual for proxy support so I had to make a slight modification to my base Entity<TId> class.

I only wrote 2 unit tests this time around, because I'm more than confident that the functionality works. Earlier I ran into a problem with my GetAll(IEnumerable<TId> ids) implementation of my BaseRepository class due to constraints that Raven enforces. I still have to come up with a clean work around, but we won't worry about that for now. This time I wanted to be sure my GetAll overload would work so I tested it in addition to Save. The tests both pass with flying colors.

The Start method of UnitOfWork becomes...

public static void Start() {
    // CurrentSession = new RavenSession();
    CurrentSession = new NHibernateSession();
}

[TestFixture]
public class ProductRepositoryTests {
    [TestFixtureSetUp]
    public void Init_Unit_Of_Work() {
        UnitOfWork.Start();
    }

    [TestFixtureTearDown]
    public void Uninit_Unit_Of_Work() {
        UnitOfWork.CurrentSession.Dispose();
    }

    [Test]
    public void Product_Repository_Can_Save() {
        var product = new Product { InventoryCount = 12, Name = "A-Dubb's World" };

        IProductRepository productRepository = new ProductRepository();

        productRepository.Add(product);

        var id = product.Id;

        Assert.IsFalse(id == Guid.Empty);
        
        product = productRepository.Get(id);

        Assert.AreEqual(12, product.InventoryCount);
        Assert.AreEqual("A-Dubb's World", product.Name);

        productRepository.Delete(product);

        UnitOfWork.CurrentSession.SaveChanges();
    }

    [Test]
    public void Product_Repository_Can_Get_All() {
        var product = new Product { InventoryCount = 12, Name = "A-Dubb's World" };

        IProductRepository productRepository = new ProductRepository();

        productRepository.Add(product);

        var id = product.Id;

        Assert.IsFalse(id == Guid.Empty);

        product = productRepository.Get(id.ToSingleEnumerable()).SingleOrDefault();

        Assert.IsNotNull(product);
        Assert.AreEqual(product.Name, "A-Dubb's World");
        Assert.AreEqual(product.InventoryCount, 12);

        productRepository.Delete(product);

        UnitOfWork.CurrentSession.SaveChanges();
    }
}





















And yea I should have followed TDD and written my tests first and I surely could have refactored my units tests for reusability's sake; but I'm not gonna bother.

Conclusion

We started out with our common session interface for NHibernate and Raven to implement. The we made our UoW and concrete Raven based session implementation. That was followed by our strongly typed classes for local storage and our core domain layer base classes (Entity and BaseRepository). We then subclasses out BaseRepository to make a Raven specific implementation that stores Entities with string based ids as Raven requires. Since we plan to be able to use Raven on the web, we made an HttpModule that can be registered in Web.config to initialize our session for each request made to our web application. And lastly, we wrapped things up with a few unit tests, a concrete ISession implementation for NHibernate, and discovered some things about Raven along the way. Specifically it can not pick up on and inherited Id property and only a specific subset of methods are allowed to be executed within our query calls/lamda expressions.

Well, that's it folks. As I mentioned before, the switch between Raven and NHibernate is a trivial but potentially problematic one, but you'd at least have your core domain layer in place for each framework. For one, Id's in Raven are string based, which is not the case in NHibernate where GUIDs tend to dominate. So switching would probably mean refactoring your entities switching the repository you inherit from; which could certainly be a problem. Secondly, it makes it tougher to use framework specific features such as indexes in Raven when executing queries; which is one its most important features. Were it not for the aforementioned constraints, you'd be able to switch from Raven to NHibernate with one line of code. That's why I build this post to begin with. I thought I could pull it off, but my unit tests told me otherwise. Either way, this was really fun to implement and I learned a lot. I hope this post proves to be helpful to a lot of people and can maybe serve as a catalyst for future implementations.

This is quite a bit of code so I should be uploading to github any day now.

I'll follow up this post by implementing a cool implementation of read only mode in ASP.NET (web forms). Pretty cool right?

Cheers!!

2 comments:

  1. I'd just like to add that I think Raven does indeed support Ids other than string. Looks like you can work with Guids and ints as well. My mistake folks.

    ReplyDelete
  2. This is a nice article..
    Its easy to understand ..
    And this article is using to learn something about it..

    c#, dot.net, php tutorial, Ms sql server

    Thanks a lot..!
    ri80

    ReplyDelete