Friday, September 9, 2011

Repository Pattern

I have been doing some (a very little bit) 'on-the-side' development using the FMSC framework with an end goal of producing a fairly simple multi-platform trade and production game. If anyone is familiar with Eve-Online, this game is based on the market from that. This is really just an excuse to work with the framework, occupy my brain, and get some ideas going.

Anyway, while doing this I came across some discussions on the "Repository Pattern", EF 4.1 and when it is and is not required. Based on this I am thinking that the "Repository" layer could be removed.



To start with, I think the "repository project" that we have right now is still required at a basic level as this is where the DBContext lives, which is the way we interact with EF, but it is the individual Repository objects / Interfaces that I think could be removed and replaced with direct calls to the EF repository object.



Why the repository

Separation of concern – each repository instance is designed to separate the data access functions from the business logic functions. This is your general DAL/BL/UI separation, where the DAL in this case is the Repository.
Flexibility – the Repository Interface should allow you to swap out the underlying ORM with minimal impact


Why our repository implementation fails

1.a) The DBContext.Set() interface is itself a repository pattern. Business operations occur on the class instances exposed by the Set operation. E.g. DBContext.Set().add(itemInstance) will add an item to the database, exactly the same as ItemRepository.Add(itemInstance), but with a whole class layer being removed.

1.b) An intent of the repository layer was to ensure that all database operations were resolved before returning to the Business Layer, which prevented the business layer from essentially creating dynamic sql statements. However, it became apparent that the repository had to be flexible enough to provide the functionality that the BL requires, which required a lot of work (such as implementing a way to specify which children to load for an entity).

By adding this flexibility we then provided the BL with more ability to dictate the SQL that was generated, ultimately negating the purpose of the repository to begin with. The only benefit the repository now provided was that all queries would be resolved as soon as the repository was called, not when the service 'resolved' the query.

The cost of implementing this flexibility was also itself expensive, especially when EF itself provided this out of the box.

2) Being able to swap out one ORM for another (e.g. EF to nHibernate) would be a particularly amazing feature and is one of the Holy Grails of the repository pattern. However, as highlighted in a few blogs I read, a) how often does this happen (I'll slap whoever mentions CBH) and b) how much actual effort would it really save.

Due to the additional flexibility that we had to include to allow the repository to be an asset rather than a hindrance, I believe we are coupled closely enough with the underlying framework that changing ORMs is possible, but potentially more effort than is feasible. The potential payoff is there (one interface for EF or NH), but if we never get there then the repository is just a waste of effort.



Conclusion

For all future work on my "Market" game I will be using the EF Set() "repository" and will attempt to identify any areas where the repository layer is actually more suitable. If I find anything I'll blog about it.

Edit, I do actually think there is one area where the repository can provide a useful function, and thanks to Brian for bringing this up. The Non-Null Pattern (or whatever you want to call it) is a pretty useful pattern, one which can be helped tremendously by the repository. E.g., calling getSingle(query) on the repository can call the Set().FirstOrDefault(query) and if null return a blank T. However if you are working on the Set directly, you will need to check for the nulls in the BL and handle it appropriately. It may be possible to use extension methods to do this (actually, that might be a very good way of handling this, note to self), but the repository pattern does make it easy.

That is about the only real tangible benefit I can see of the repository however.

No comments:

Post a Comment