Tired of looking for errors in log files? Use OneTrueError - Automatic exception management for .NET.

Generic repositories – A silly abstraction layer

This post is all about GENERIC repositories as in Repository, not about all types of repositories. Repositories are a great way to abstract away the data source. Doing so makes your code testable and flexible for future additions.

My recommendation is against generic repositories, since they don’t give you any additional value compared to regular repository classes. “Regular” repositories are usually written specifically for the requirements that your project have.

Let’s look at what generic repositories give you:

You can change OR/M implementation at any time.

Seriously?

  1. If you find yourself having switch OR/M during a project you have not done you homework before you started the project.
  2. The OR/M choice doesn’t matter since you have abstracted away the features of the chosen OR/M

imho you’ll stick with one OR/M during a project and switch for the next one (if you have to switch).

You have to write less code.

Here is a Generic repository (nhibernate implementation) from a SO question:

public interface IRepository<T> : IQueryable<T>
{
  void Add(T entity);
  T Get(Guid id);
  void Remove(T entity);
}

public class Repository<T> : IQueryable<T>
{
  private readonly ISession session;

  public Repository(ISession session)
  {
    session = session;
  }

  public Type ElementType
  {
    get { return session.Query<T>().ElementType; }
  }

  public Expression Expression
  {
    get { return session.Query<T>().Expression; }
  }

  public IQueryProvider Provider
  {
    get { return session.Query<T>().Provider; } 
  }  

  public void Add(T entity)
  {
    session.Save(entity);
  }

  public T Get(Guid id)
  {
    return session.Get<T>(id);
  }

  IEnumerator IEnumerable.GetEnumerator()
  {
    return this.GetEnumerator();
  }

  public IEnumerator<T> GetEnumerator()
  {
    return session.Query<T>().GetEnumerator();
  }

  public void Remove(T entity)
  {
    session.Delete(entity);
  }   
}

Take a look at the methods. All they do is to call methods in nhibernate. You do not win anything by doing so. All you get is an abstraction layer that removes the good things with nhibernate/ef/whatever.

It’s better to create a proper base class and move all repeated (DRY) functionality into it (and therefore still be able to take advantage of the features in your favorite OR/M).

Summary

Did I miss something that a generic repository gives you? Please make a comment.

This entry was posted in Architecture, CodeProject and tagged . Bookmark the permalink.
  • chris

    While I agree that creating a “Repository” that is just a wrapper for ISession.Query doesn’t add any value and the two motivations you mentioned for doing that are silly, I don’t agree that the notion of a generic repository should be completely dismissed. I think it does make sense if you combine it with the Specification pattern (e.g. LinqSpecs) instead of adding specific query methods to your non-generic repository. To me this just feels more elegant than having non-generic Repositories with dozens of query methods for every possible use case.

    Take a look at (an excerpt of) my implementation:

    public class NHRepository : IRepository 
    {
        public ISessionFactory SessionFactory { get; set; } 
        public void Add(T entity) 
        {
            SessionFactory.GetCurrentSession().Persist(entity);
        }
        // ...
        public IEnumerable FindAll(LinqSpecs.Specification spec)
        {
            return SessionFactory.GetCurrentSession().Query()
                .Where(spec.IsSatisfiedBy()).ToList();
        }
    }
    

    An important point about this implementation is that I consciously avoid returning the (lazily evaluated) expression tree (i.e. IQueryable) but force its evaluation by calling ToList(). This forces users to actually write Specifications rather than distributing their query logic all over the place by manipulating the expression tree (which would defeat the purpose of having a Repository in the first place).

    • http://www.gauffin.org jgauffin

      It escapes code if you use the proper tag ;)

      Well. Yes. Generic repository with specifications do add more value. The orm features are still lost.

      • chris

        Well, ORM features (and possibly easier optimization) are a valid point, I give you that. Still I think generic Repositories are not necessarily silly when done right.

        • http://www.gauffin.org jgauffin

          Of course. As with most things, doing it right can make it better. But for what purpose? Why do you pick it over your ORM or a custom repository class?

          • chris

            Because I am hoping to avoid bloated interfaces for my repositories with dozens of query methods. Also better reuse through chaining of specifications.