IRepository: one size does not fit all

I’ve been spending a lot of time putting TDD/DDD into practice lately, and obsessing over all sorts of small-yet-important details as I try concepts and patterns for myself.

One pattern that has recently become popular in mainstream .NET is IRepository<T>. Originally documented in PoEAA, a repository is an adapter that can read and write objects from the database as if it were an in-memory collection like an array. This is called persistence ignorance (PI), and lets you forget about underlying database/ORM semantics.

Somewhere along the line however, someone realized that with generics you can create a single, shared interface that will support pretty much any operation you could ever want to do with any sort of object. They usually look something like this:

public interface IRepository<T>
{
    T GetById(int id);
    IEnumerable<T> GetAll();
    IEnumerable<T> FindAll(IDictionary<string, object> propertyValuePairs);
    T FindOne(IDictionary<string, object> propertyValuePairs);
    T SaveOrUpdate(T entity);
    void Delete(T entity);
}

If you need to add any custom behaviour, you can simply subclass it — e.g. IProjectRepository : IRepository — and add new methods there. That’s pretty handy for a quick forms-over-LINQ-to-SQL application.

However, I don’t believe this is satisfactory for applications using domain-driven design (DDD), as repositories can vary greatly in their capabilities. For example, some repositories will allow aggregates to be added, but not deleted (like legal records). Others might be completely read-only. Trying to shoehorn them all into a one-size-fits-all IRepository<T> interface will simple result in a lot of leaky abstractions: you could end up with a Remove() method that is available but always throws InvalidOperationException, or developer team rules like “do not never call Save() on RepositoryX”. That would be pretty bad, so what else can we do instead?

Possibility #2: no common repository interface at all

The first alternative is simply dropping the IRepository<T> base, and make a totally custom repository for each aggregate.

public interface IProjectRepository
{
    Project GetById(int id);
    void Delete(Project entity);
    // ... etc
}

This is good, because we won’t inherit a bunch of crap we don’t want, but similar repositories will have a lot of duplicate code. Making method names consistent is now left to the developer — we could end up with one repository having Load(), another Get(), another Retrieve() etc. This isn’t very good.

Thinking about it, a lot of repositories are going to fit into one or two broad categories that share a few common methods — those that support reading and writing, and those that only support reading. What if we extracted these categories out into semi-specialized base interfaces?

Possibility #3: IReadOnlyRepository and IMutableRepository

What if we provided base interfaces for common repository types like this:

IReadOnlyRepository and IMutableRepository

This is better, but still doesn’t satisfy all needs. Providing a GetAll() method might be helpful for a small collection of aggregates that we enumerate over often, but it wouldn’t make so much sense for a database of a million customers. We still need to be able to include/exclude standard capabilities at a more granular level.

Possibility #4: Repository Traits

Let’s create a whole load of little fine-grained interfaces — one for each standard method a repository might have.

public interface ICanGetAll<T>
{
    IEnumerable<T> GetAll();
}

public interface ICanGetById<TEntity, TKey>
{
    TEntity GetById(TKey id);
}

public interface ICanRemove<T>
{
    void Remove(T entity);
}

public interface ICanSave<T>
{
    void Save(T entity);
}

public interface ICanGetCount
{
    int GetCount();
}

// ...etc

I am calling these Repository Traits. When defining a repository interface for a particular aggregate, you can explicitly pick and choose which methods it should have, as well as adding your own custom ones:

public interface IProjectRepository :
    ICanSave<Project>,
    ICanRemove<Project>,
    ICanGetById<Project, int>,
    ICanGetByName<Project>
{
    IEnumerable<Project> GetProjectsForUser(User user);
}

This lets you define repositories that can do as little or as much as they need to, and no more. If you recognize a new trait that may be shared by several repositories — e.g., ICanDeleteAll — all you need to do is define and implement a new interface.

Side note: concrete repositories can still have generic bases

Out of interest, here’s what my concrete PersonRepository looks like:

Concrete NHibernateRepository and PersonRepository

There’s very little new code in it, because all of the common repository traits are already satisfied by a generic, one-size-fits-all NHibernateRepository base class (which must be completely hidden from external callers!). The IPersonRepository just defines which subset of its methods are available to the domain layer.

January 19, 2009

14 Comments

Andrew Jackman on January 19, 2009 at 9:49 pm.

This is called the “favour composition over inheritance” approach. See http://www.artima.com/lejava/articles/designprinciples4.html and http://www.objectmentor.com/resources/articles/inheritanceVsDelegation.pdf.

Matt Freeman on January 21, 2009 at 9:48 am.

I’m definitely leaning towards a generic DAO style inner repository, and concrete implementation of a domain repository containing this.

Part of the domain would be IPersonRepository exposing clear methods like GetPersonByFirstName(string firstName) etc… This would be implemented by a concrete repository that lives outside your domain that contains a nested concrete generic DAO style repository exposing Load FindAll etc…

Vasilio Ruzanni on April 12, 2009 at 4:31 am.

It seems like we can almost clearly separate the concepts of “Domain Repositories” (and Domain Repositories Traits) and “Data Access Repositories”.

Should we?

Vasilio Ruzanni on April 12, 2009 at 4:41 am.

2Richard

And also I’d better tend to instead (of inheritance) delegate data-access functions to NHibernateRepository by using it inside ProjectRepository.

That’s just because I can’t clearly see any reason to inherit from it. Is there one?

Richard on April 12, 2009 at 11:06 am.

@Vasilio: my concrete repository is connected directly to NHibernate because the ORM easily allows this, and there is no additional logic in the repository (nor should there be, it’s just a collection).

In more complex mapping scenarios you might use a DAO-backed repository – see this article for the difference http://warren.mayocchi.com/2006/07/27/repository-or-dao/.

Christian Horsdal on June 25, 2009 at 9:57 pm.

Very good post. I definitely like way you split the repository interface into little self-contained traits.
Combining your approach with a few extension methods creates traits that carry implementation with them. That implementation is easily reused between concrete repositories. I show this approach in a blog post at http://horsdal.blogspot.com/2009/06/exploring-wpf-business-application_24.html/ …and hey, I think it turns out pretty nicely :-)

Christian Horsdal on June 25, 2009 at 9:58 pm.

Oops I got the link wrong. It’s: http://horsdal.blogspot.com/2009/06/exploring-wpf-business-application_24.html

Nan Vantrease on September 21, 2009 at 9:45 am.

wei? nicht, wie Ihr Blog kam, muss ein Tippfehler gewesen sein,

Phillip Givens on September 23, 2012 at 2:08 am.

Thank you very much for posting this! I have been forever crusading against this horrible, yet popular, pattern.

Richard on September 23, 2012 at 11:03 am.

@Phillip: Jimmy Bogard over at Los Techies also has some good discussion about this pattern: http://lostechies.com/jimmybogard/2012/09/20/limiting-your-abstractions/

Thiago Silva on January 18, 2013 at 7:49 pm.

@Richard do you have a sample solution and project structure on GitHub or something so I can see a bigger picture? How do you usually structure your projects with this kind of architecture? Do you put these interfaces in the Domain project, or in the same project as the implementation of the repositories? (and yes, i’ve read Jimmy’s recent blog post on project structures, but I am working on a fairly large and complex system that warrants a structured approach). Thanks

Richard on January 19, 2013 at 2:39 pm.

@Thiago: I would recommend looking at Ayende’s Macto, a sample “prison management application” written using DDD.

Background and design notes: http://ayende.com/blog/tags/macto
Code: https://github.com/ayende/Macto/

And I wouldn’t use split code into separate projects (DLLs) unless they are being packaged and deployed separately. If you are just producing one .exe, or one web app, then it will be much faster to put everything in the same project/assembly and use namespaces.

Thiago Silva on January 21, 2013 at 4:44 pm.

@Richard I dug through Ayende’s app, which hasn’t been updated in 2 yrs. It doesn’t even resemble the problem and requirements of my app and architecture, so it’s not much help to me.

Also, I do need things separated because it’s a cloud app with web and worker roles that access same domain models, EF entities, etc.

Peter Morris on October 12, 2014 at 6:35 pm.

I create an interface per repository, no inheritance at all. It’s only the implementation I use inheritance for, I create a generic Repository and then subclass + override where needed. So I get common behaviour but only expose via the interface what is logical for the currecn object.

Leave a Reply