One of my favorite design patterns is the 'repository pattern'. That's why I decided to dedicate a complete blog post to it. Using the repository pattern in your application can yield a lot of benefits, such as improved testability, easier ways to implement caching and transactions, avoidance of code duplication and it allows you to replace the data source easier (although that probably won't happen too often).
Improved testability
Putting an additional layer between your business logic and the data source instead of querying the data source directly from the business logic layer improves the testability because it allows you to replace this layer (the repository) so that you no longer have to use the database when running unit tests. Instead you can just focus on testing your business logic. This improves the stability, flexibility and performance of your unit tests.
Caching and transactions
Because you have all the logic for querying and persisting in one place, you can easily implement caching in one place. The same goes for transactions. A good combination is to implement the Unit of Work pattern in your repository, so you 'queue' all data that needs to be persisted and persist them all together when you tell the Unit of Work to commit. This allows you to execute multiple actions and commit afterwards, or roll back when an exception gets thrown.
The Repository
There are several ways to implement the repository pattern; one could create one repository for each table in the database (e.g. CustomerRepository, OrderRepository, etc.) or one could create a generic repository that provides generic functionality that applies to all tables.
Below is an example of a repository class made for a specific table (the imaginary Account table) and it's interface:
public interface IAccountRepository
{
IEnumerable<Account> List();
Account First();
Account Last();
Account Find(int id);
void Insert(Account account);
void Update(Account account);
void Delete(Account account);
void Commit();
void Rollback();
}
public class AccountRepository : IAccountRepository
{
public IEnumerable<Account> List()
{
// return some stuff
}
public Account First()
{
// return some stuff
}
public Account Last()
{
// return some stuff
}
public Account Find(int id)
{
// return some stuff
}
public void Insert(Account account)
{
// do some stuff
}
public void Update(Account account)
{
// do some stuff
}
public void Delete(Account account)
{
// do some stuff
}
public void Commit()
{
// commit the changes
}
public void Rollback()
{
// roll back all changes
}
}
As you can probably see we could make this repository generic (actually it already is pretty much generic). There have been a lot of discussions on this subject. Many people tried making a generic interface, but very often such an implementation doesn't work in practice. For example: not every entity allows updating or deleting. Some tables have some very specific actions that are executed very often. Trying to abstract this any further by making a generic interface will probably hurt more than it solves.
Using the repository
Now that we've created the repository we can use it to do some great stuff. Below is a very simple and naive example that shows you one usage of the repository:
public class AccountController : Controller
{
private readonly IAccountRepository _accountRepository;
public AccountController(IAccountRepository accountRepository)
{
_accountRepository = accountRepository;
}
[HttpPost]
public ActionResult New(Account account)
{
_accountRepository.Insert(account);
return View();
}
}
So what I've done here is create a simple ASP.NET MVC3 project, with a controller that has a constructor that takes a repository class that implements IAccountRepository. We also have a little action method that creates a new account. I've skipped some very important stuff like input validation because that's not the point here. The most important part is the fact that I pass an IAccountRepository object to the controller. Normally this would just be an AccountRepository object, but this could also be a mock/stub (fake) object. This means that we could just inject (this is a hint to 'Dependency Injection') another class that implements IAccountRepository, with methods that actually do... Nothing. This is also called loose coupling.
As you can probably see, this allows us to run unit tests without depending on the database. We could just work with in-memory objects. This yields a lot of benefits: it's faster, it doesn't mess with your database (in fact: you don't even NEED a database anymore) and thereby allowing you to run your unit tests everywhere without having to configure a database everywhere.
To make things every easier we can just use a dependency injection container that maps IAccountRepository to AccountRepository, so we don't have to inject an AccountRepository object manually all the time.
Conclusion
The Repository pattern is one very useful pattern that extremely improves the testability of your application, as well as providing other benefits such as easier ways to implement caching and transactions. By using dependency injection we can decouple the data source from the business logic.