Using the Repository Pattern with ActiveRecord from Castle
I first learned about ActiveRecord (AR) when I was introduced to the MonoRail framework made by Castle. Then a few years later I started to learn about Domain-Driven Design (DDD) and found that is was an interesting way to design software. Just like so many other software design techniques, DDD also uses design patterns and one of them is the Repository Pattern.
Repository - A mechanism for encapsulating storage, retrieval, and search behaviour which emulates a collection of objects.
– Eric Evans, Domain-driven design
Usually when you use ActiveRecord from Castle, then your entities would have to inherit from a base class like ActiveRecordBase, but in this example we don’t need to do that anymore.
You need to have some basic understanding of ActiveRecords, NHibernate and the Repository Pattern to implement the example.
1 2 3 4 5 6 7 | public interface IRepository<T> { T FindBy(Guid id); IList<T> FindAll(); void Save(T item); void Delete(T item); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class RepositoryBase<T> : IRepository<T> where T : IAggregateRoot { public T FindBy(Guid id) { return (T)ActiveRecordMediator.FindByPrimaryKey(typeof(T), id); } public IList<T> FindAll() { return (IList<T>)ActiveRecordMediator.FindAll(typeof(T)); } public virtual void Save(T item) { ActiveRecordMediator.Save(item); } public virtual void Delete(T item) { ActiveRecordMediator.Delete(item); } } |
The IAggregateRoot is just a marker interface, meaning that it doesn’t specify any functionality. I know that this might look like “code smell” to some, but it really depends on what you are trying to achieve.
Custom attributes are preferred when you can defer checking for the attribute until the code is executing. If your scenario requires compile-time checking, you cannot comply with this guideline.
- MSDN, Guidelines for developing Class libraries.
The problem with using AR with DDD
Well, PI means clean, ordinary classes where you focus on the business problem at hand without adding stuff for infrastructure-related reasons.
– Applying DDD and Patterns, Jimmy Nilsson
Using AR will you get up and running pretty fast, but you might want to remove the AR parts later on and then re-implement your repository to only use NHibernate. The reason for this is that entities shouldn’t know about how they are persisted (i.e. Persistence Ignorance) and when you apply them with AR attributes they do.
If you want to achieve a higher Persistence Ignorance, then you could try out Ayende’s Rhino-Tools (also know as rhino-commons). There you can find a better implementation of the Repository Pattern, which also uses NHibernate. Another solution would of course be to create one your self.
Further reading
Domain-Driven Design: Tackling Complexity in the Heart of Software
Applying Domain-Driven Design and Patterns: With Examples in C# and .NET