Repository Design Pattern in C# Part 1

This is part one of a two part series. This post covers the thought process that I often go through when implementing the repository design pattern. The next post will show a complete implementation.

The repository design pattern has become very popular in the .NET ecosystem in recent years mainly because it is a simple data access abstraction that can be easily implemented, easily tested, and easily built on top of Entity Framework, LINQ2SQL, and other ORMs. In this post, I will walk you through the implementation of the repository design pattern in C#.

Before getting started, it is important to understand that while there is not a set way a repository must look, there is an expectation on how the repository should behave. When designing my own repositories, I try to keep the rules listed below in mind.

  1. Repositories access and manipulate data. This includes CRUD operations.
  2. Repositories do not contain any business logic.
  3. Repositories can provide statistics like counts.
  4. Repositories can filter data.
  5. There isn’t a limit on the number of methods on a repository.
  6. One object per file. If you have two different objects in your model (ie Customers and Orders), you should have two different repositories (CustomerRepository and OrderRepository).

It is also worthwhile to examine some of the pros and cons of the repository pattern.

Pros

  1. Repositories should be bound to interfaces which makes them easily testable.
  2. Provides a single source of data manipulation. This supports DRY (don’t repeat yourself) leaving you with a cleaner code base.
  3. Provides an easy route to separation of concerns. All data access code is in a single set of classes and doesn’t spill over into other classes.

Cons

  1. Is yet another layer of abstraction in our code which complicates understanding and can sometimes hide problems.
  2. To be effective, you have to compromise in either readability (many methods) or functionality (generic repository – I almost always compromise on readability because I hate testing generic repositories).

Before implementing this pattern, I suggest you sit and think about some of the decisions you will be making.

  1. Will you return nulls for methods that do not have a valid return value? This impacts the code you write because if you are going to allow nulls, you probably have to write some code in your calling methods to check for that return value being null. If you aren’t going to allow nulls, you have to catch exceptions.
  2. Will your repositories be fine grained or coarse grained? This will have a major impact on how thin your repositories are. If you are going for coarse grained, you can probably adhere to a common interface across different repositories while not doing the Generic Repository pattern. If you are going fine grained, you will likely have larger repositories, more interfaces, and less data-centric code in your logic. I will show an example of both below.

 

Fine Grained

public interface ICustomerRepository
{
    void Add(Customer customer);
    void Delete(Customer customer);
    IQueryable<Customer> GetAllCustomers();
    Customer GetCustomerByID(int id);
    void Update(Customer customer);
}

In a true repository, you might have 5-10 or even more methods to retrieve the data you are after for any given calling method. You might also want to pass in an entire list of customers to add or delete.

Coarse Grained

public interface IOrderRepository
{
    void Add(Order order);
    void Delete(Order order);
    IQueryable<Order> GetOrders(Expression<Func<Order, bool>> predicate);
    void Update(Order order);
}

This allows an entire where clause to be passed in to return data. This flexibility comes at a cost, however. That where clause has to be constructed somewhere and might end up in your business logic.

 

Since the repository pattern allows for some flexibility, it is very helpful to have some thought process before and during implementation. In the next post, we will do just that and create an implementation for both of the interfaces listed above.

Comments 1

  1. Pingback: Repository Design Pattern in C# Part 2 | JasonBentley.net Blog

Leave a Reply

Your email address will not be published.