What’s it all about?
When talking about both Linq to Sql (L2S) and Entity framework (EF) you will frequently hear developers saying that they will be using a repository to encapsulate the ORM interactions, what this means in practice is hiding the actual ORM functions and providing a abstract class or interface you can mock to make it easier to test your applications.The simplest way of doing this is simply creating a class per entity that implements an interface and allows you to mock/stub/fake the interactions with the ORM allowing for easier unit testing of logic.
Hasn’t this been done before?
Yes it has. There are lots of articles on the web in relation to creating repositories and in particular generic repositories.The majority of the articles I found were around EF but there were also versions for L2S and NHibernate.
So why did you create one?
At the time I started to create my own generic repository I had been using L2S for a while but found it frustrating that although it was useful it made testing very difficult as there was no easy way to mock/stub/fake it.So I decided to try and create my own, yes I could have just used one that was already on the internet but doing that I wouldn’t have really thought about what was needed or what issues I could encounter.
It would be very churlish of me to pretend that I hadn’t looked at other peoples implementations especially since the issues I was running into may have already been solved by other people (this post in relation to the L2S implementation and this post in relation to the EF implementation).
Does this code offer anything different?
My code has been designed to work with dependency injection and because of this each repository class does not create the context it needs rather it expects it to be injected into it. Its not revolutionary but does allow the developer to control the lifetime of the context rather than relying on the repository to do so.The implementations for L2S & EF have been designed to work with entities that have been disconnected from a context rather than simply expecting all the interactions to be done within the scope of a single context which is often an issue in
n-tier applications.
A fair number of the generic repository implementations I found on the web expected you to not only specify the type but also the primary key, my implementations will attempt to determine the primary key of the entity itself removing the need to specify this.
Why use generic repositories?
The advantages
Generic repositories are perfect when building applications using TDD and you need to be able to mock/stub/fake the ORM as a dependency. It is also possible to take a lot of boiler plate code (such as updating changes in a disconnected scenario) and push it into the repository so keeping the code DRY and adhering to SOLID principles.The other major advantage is the ability to inject the ORM dependency into other classes allowing you utilise IoC containers to construct whatever object graph is required.
The disadvantages
The generic repository as I, and most other examples, have implemented it is a leaky abstraction as the entities in the ORM are what the rest of the code uses thereby creating a tight coupling between the application code and the specific ORM. This may or may not be an issue for you depending on whether you are happy to be bound to any specific ORM or if you truly want persistent ignorance.Although the generic repository offers a lot of control if your entities contain child objects you still don’t have control over it when how those are loaded, they are still loaded by the ORM and potentially if the entity has been disconnected you could have errors to contend with as it tries to load them without a context.
By encapsulating the ORM behind a facade interface it is possible you will lose some (all?) of the in built functionality that the ORM provides (self tracking entities is one possible loss) which could render the advantages of using an ORM null and void.
Summary
Whilst writing this code it struck me that the generic repository is an imperfect solution to the problem of mocking/stubbing/faking an ORM to reduce the coupling between the layers and since I first starting looking at this various solutions have come about – EF Code First, micro-ORM’s (Massive, Dapper, Simple.Data) and these provide a better solution BUT they rely on dynamic and if you are still working with .Net 3.5 this isn’t available.So if you’re on .Net 4 (or above) then look to one of the newer version of ORM or micro-ORM that will easily allow you to mock/stub/fake the data access without the need for this additional coding, however, if you are working with .Net 3.5 then a generic repository may just be what you need to enable you to utilise an ORM, unit test the code and use IoC to create your object graph.
The code itself is available to download from my GitHub, please go here to download it.
Note: the code has been written in .Net 4.0 whilst L2S is happy to convert to .Net 3.5 the EF implementation will need rewriting to work.
Great post with some valid points.
ReplyDeleteMy love for the repository pattern has somewhat diminished of late, having found it to be increasingly more of a hindrance than a help, specifically with NHibernate; the repositories take a dependency on ISession and are unable to expose the richness of options that ISession has. Personally, I feel that one of NHibernate's greatest powers come from the ability to choose how entities will be hydrated in each case and I find that I end up trying to circumvent this with the repository pattern by introducing specific methods for specific cases, or implementing some kind of query object / specification pattern.
Indeed, Ayende has argued in the past (http://ayende.com/blog/3955/repository-is-the-new-singleton) that NHibernate already provides the Repository abstraction itself and hence it is unnecessary to wrap it further, unless of course it's possible that you could ever envisage swapping out the underlying persistence implementation :)
For .NET 3.5, you can use ServiceStack's OrmLite: https://github.com/ServiceStack/ServiceStack.OrmLite
ReplyDeleteWorks without the full ServiceStack stack, and supports multiple databases.