Click here to Skip to main content
15,867,756 members
Articles / Web Development / ASP.NET
Article

Understanding and Implementing Repository and Unit of Work Pattern in ASP.NET MVC Application

Rate me:
Please Sign up or sign in to vote.
4.90/5 (33 votes)
12 Apr 2013CPOL6 min read 138.8K   3K   75   24
In this article we will try to see what is Repository and Unit of Work Pattern in an ASP.NET MVC application.

Introduction

In this article we will try to see what is Repository and Unit of Work Pattern in an ASP.NET MVC application. We will also implement a small rudimentary sample application to understand the same.

Background 

Possibility of using ORMs in our application saves us from a lot of code that needs to be written in order to create our entities and data access logic. But using ORMs like entity framework sometimes lead to scattered data access logic/predicates in various place in code.

Repository and Unit of work pattern provides a clean way to access data and at the same time maintain the test-ablility of the application. Let us try to understand this by implementing a simple ASP.NET MVC application.

Using the code

Let us first try to create a simple database on which we will be performing CRUD operations. We will define a simple tables in the database as:

Image 1

Now with the database/table in created, we will go ahead and generate the ADO.NET entity data Model for these tables in our application. The generated entities will look like:

Image 2

Performing Simple Data Access

Now we have the entity framework ready to be used in our application. We can very well use the Context class in each controller to perform database operations. Let us try to see this by trying to retrieve the data in our Index action of HomeController.

C#
public ActionResult Index()
{
    List<Book> books = null;

    using (SampleDatabaseEntities entities = new SampleDatabaseEntities())
    {
        books = entities.Books.ToList();
    }

    return View(books);
}

And when we try to run this application, we will see that it is getting the data from the database as:

Image 3

Note: We will not be doing other CRUD operations here because they can be done on same lines very easily.

To visualize the above implementation:

Image 4 

Now there is nothing wrong from the code and functionality perspective in doing this. But there are two problems in this approach.

  1. The Data access code is scattered across the application and this is a maintenance nightmare.
  2. The Action in the Controller is creating the Context inside itself. This makes this function non testable using dummy data and we can never be able to verify the results unless we use test data.

Note: If the second point is not clear then it is recommended to read about Test Driven Development using MVC. We cannot discuss it in this article otherwise the article will become digressing.

Creating a Repository

Now how can we solve the problem. We can solve the problem by moving all the data access code of entity framework in one place. So let us define a class that will contain all the data access logic for

Books
table.

But before creating this class, let us also think about the second problem for an instance. If we create a simple interface defining the contract for accessing the books data and then implement this interface in our proposed class, we will have one benefit. We can then have another class implementing the same interface but playing around with the dummy data. Now as long as the controller is using the Interface our test projects can pass the dummy data class and our controller will not complain.

So let us first define the contract for accessing books data.

C#
// This interface will give define a contract for CRUD operations on
// Books entity
interface IBooksRepository
{
    List<Book> GetAllBooks();
    Book GetBookById(int id);
    void AddBook(Book book);
    void UpdateBook(int id, Book book);
    void DeleteBook(Book book);
    void Save();
}

And the implementation of this class will contain the actual logic to perform the CRUD operations on the Books table.

C#
public class BooksRepository : IBooksRepository, IDisposable
{
    SampleDatabaseEntities entities = new SampleDatabaseEntities();

    #region IBooksRepository Members

    BooksRepository()
    {
        entities = new SampleDatabaseEntities();
    }

    public List<Book> GetAllBooks()
    {
        return entities.Books.ToList();
    }

    public Book GetBookById(int id)
    {
        return entities.Books.SingleOrDefault(book => book.ID == id);
    }

    public void AddBook(Book book)
    {
        entities.Books.AddObject(book);
    }

    public void UpdateBook(int id, Book book)
    {
        Book b = GetBookById(id);
        b = book;
    }

    public void DeleteBook(Book book)
    {
        entities.Books.DeleteObject(book);
    }

    public void Save()
    {
        entities.SaveChanges();
    }
    
    #endregion

    #region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
        
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing == true)
        {
            entities = null;
        }
    }

    ~BooksRepository()
    {
        Dispose(false);
    }

    #endregion
}

Now let us create a simple Controller in which we will have the reference to this class being used perform the CRUD operations on Books table.

C#
public class BooksController : Controller
{
    private IBooksRepository booksRepository = null;

    public BooksController()
        :this(new BooksRepository())
    {

    }

    public BooksController(IBooksRepository bookRepo)
    {
        this.booksRepository = bookRepo;
    }

    public ActionResult Index()
    {
        List<Book> books = booksRepository.GetAllBooks();
        return View(books);
    }
}

Now here in this above code when the application runs the default parameter-less constructor will run which will create a BooksRepository object and it will be used in the class. The result of which is that the application will be able to work with actual data from the database.

Now from our test project we will call the parameterized constructor with an object of the dummy class containing dummy data. The benefit of which is that we should be able to test and verify the controller classes using the dummy data.

Lets run the application to see the output

Image 5 

Note: We will not be doing other CRUD operations here because they can be done on same lines very easily.

Lets try to visualize this version of implementation

Image 6 

Having Multiple Repositories

Now imagine the scenario where we have multiple tables in the database. Then we need to create multiple repositories in order to map the domain model to the data model. Now having multiple repository classes poses on problem.

The problem is regarding the ObjectContext object. If we create multiple repositories, should they contain their ObjectContext separately? We know that using multiple instances of

ObjectContext
object simultaneously can be a problem so should we really allow each repository to contain their own instances?

To solve this problem. Why to let each Repository class instance have its own instance of the ObjectContext. Why not create the instance of ObjectContext in some central location and then pass this instance to the repository classes whenever they are being instantiated. Now this new class will be called as UnitOfWork and this class will be responsible for creating the ObjectContext nstance and handing over all the repository instances to the controllers.

Unit Of Work

So let us create a separate Repository to which will be used via UnitOfWork class and the ObjectContext will be passed to this class from outside.

C#
public class BooksRepositoryEn
{
    SampleDatabaseEntities entities = null;        

    public BooksRepositoryEn(SampleDatabaseEntities entities)
    {
        this.entities = entities;
    }

    public List<Book> GetAllBooks()
    {
        return entities.Books.ToList();
    }

    public Book GetBookById(int id)
    {
        return entities.Books.SingleOrDefault(book => book.ID == id);
    }

    public void AddBook(Book book)
    {
        entities.Books.AddObject(book);
    }

    public void UpdateBook(int id, Book book)
    {
        Book b = GetBookById(id);
        b = book;
    }

    public void DeleteBook(Book book)
    {
        entities.Books.DeleteObject(book);
    }

    public void Save()
    {
        entities.SaveChanges();
    }
}

Now this Repository class is taking the ObjectContext object from outside(whenever it is being created). Also, we don't need to implement IDisposable here because this class is not creating the instance and so its not this class's responsibility to dispose it.

Now if we have to create multiple repositories, we can simply have all the repositories take the

ObjectContext
object at the time of construction. Now let us see how the UnitOfWork class creates the repository and passes it on to the Controller.

C#
public class UnitOfWork : IDisposable
{
    private SampleDatabaseEntities entities = null;

    // This will be called from controller default constructor
    public UnitOfWork()           
    {
        entities = new SampleDatabaseEntities();
        BooksRepository = new BooksRepositoryEn(entities);
    }

    // This will be created from test project and passed on to the
    // controllers parameterized constructors
    public UnitOfWork(IBooksRepository booksRepo)
    {
        BooksRepository = booksRepo;
    }

    public IBooksRepository BooksRepository
    {
        get;
        private set;
    }

    #region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
        
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing == true)
        {
            entities = null;
        }
    }

    ~UnitOfWork()
    {
        Dispose(false);
    }

    #endregion
}

Now we have a parameter-less constructor which will be called from controller default constructor i.e. whenever our page runs. We also have a parameterized constructor which will be created from test project and passed on to the controllers parameterized constructors.

The dispose pattern is now implemented by the UnitOfWork class because now it is responsible for creating the ObjectContext so it should be the one disposing it.

Let us look at the implementation of the Controller class now.

C#
public class BookEnController : Controller
{
    private UnitOfWork unitOfWork = null;

    public BookEnController()
        : this(new UnitOfWork())
    {

    }

    public BookEnController(UnitOfWork uow)
    {
        this.unitOfWork = uow;
    }

    public ActionResult Index()
    {
        List<Book> books = unitOfWork.BooksRepository.GetAllBooks();
        return View(books);
    }
}

Now the test-ablity of this controller is still maintained by having the combination of default and parameterized constructor. Also, the data access code is now centralized in one place with the possibility of having multiple repository classes being instantiated at the same time. Let us run the application.

Image 7

Note: We will not be doing other CRUD operations here because they can be done on same lines very easily.

And finally let us visualize our implementation with Unit of Work in place.

Image 8 

Point of interest

In this article we saw what is Repository and Unit of work pattern. We have also seen a rudimentary implementation for the same in an ASP.NET MVC application. The next step to the project would be to convert all the repository classes into one generic repository so that we don't need to create multiple repository classes. I hope this has been informative.

History

  • 12 April 2013: First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India

I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems. IMO, C# is the best programming language and I love working with C# and other Microsoft Technologies.

  • Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development with Microsoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com[^]

  • Microsoft MVP 2015

Comments and Discussions

 
GeneralMy article on this Pin
Halil ibrahim Kalkan12-Apr-13 2:44
Halil ibrahim Kalkan12-Apr-13 2:44 
Hi,

I've written an article on nearly this subject. You can see it here: Dependency Injection and Unit Of Work using Castle Windsor and NHibernate[^]

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.