Click here to Skip to main content
Click here to Skip to main content

Repository Pattern and Unit of Work with Entity Framework in ASP.NET MVC

, 10 Dec 2013
Rate this:
Please Sign up or sign in to vote.
Repository pattern and Unit of Work with Entity Framework in ASP.NET MVC.

Introduction

Repository pattern is used to create an abstraction layer between the data access layer and the business logic layer. This abstraction layer contains data manipulation methods which communicate with the data access layer to serve data as per the business requirements to the logical layer. The main purpose to create this layer is for isolating data access layer so that changes cannot affect the business logic layer directly.

For example, a POS application is usually deployed to different stores. A few new clients wanted to use the Microsoft SQL Server database system and some others wanted Oracle and other databases. Also they had a few different relational database systems to store their data but business logic was almost the same. Repository pattern helps developers to detach the layer and add a new data access layer.

Unit of work is a pattern to handle transaction during data manipulation using the Repository pattern. So we can say, according to Martin Fowler, Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problem.

Implementing these patterns can help insulate the application from changes in the data store and also gives advantages to automate unit testing. Though these patterns are widely used for DDD, they facilitate for TDD also.

What is ORM and EF

Object-relational mapping is a programming technique for converting data between incompatible type systems in relational databases and object-oriented programming languages.

We can handle objects/models as a schema of the database object. We can write code/query on model object collections which load data by maintaining database relations.

Advantages of ORM

  • Data manipulation (CRUD) is handled without writing SQL queries
  • Data mapping between result set and entity collection/entity is one of the major features of ORM
  • Using UoW/Context, it can handle the transaction during data manipulation
  • Writing one Data Model in a single place for managing the model’s storage in DB.
  • It fits the natural way of coding with application’s language.
  • Programmers can think fully object oriented way to make any operation with business logic layer and data storage.

So nowadays, nobody should think of using DAO or a traditional approach to access a database if there is no special purpose; using ORM not only reduces writing code but also helps us to think only with business objects or data objects.

Entity framework is a popular object relational mapper that enables .NET developers to work with relational data using domain-specific objects. This framework supports to write POCO and generate database and is also able to create model from existing database. To know more details of the Entity framework, please visit this link.

Design your Independent/Generic repository functionality.

Now you can write different repository class for each entity. But for database operation, few common methods will be used for CRUD operation and others. So using different repository creates redundant code to the application. That’s why you should create the generic repository.

To design an independent or generic repository, follow the below steps:

In the first step, you have to create an ASP.NET MVC web application to store personal contacts. Please open a new project to choose the template ASP.NET MVC 4 Web Application.

Then add another project to solution for data access named Contact.Repository.

Create a database for the application with the following tables:

Now jump to the code and add an ADO.NET Entity Data Model to your Contact.Repository and update the model using a database to add database tables.

You will have the following edmx as the designer view:

Look at the above object, every object has been created with their associated objects which are called Navigation Properties. Now adding a reference Contact.Repository to the web project, you can start development. But the initial intention was to make a Repository layer over the Entity Data Model to access the database from the web project or the business logic layer. This example does not have any business logic layer because it is a short example but it’s a good practice to separate the business logic layer.

Add the below class to your Contact.Repository class as well as its required interfaces.

Fig: Interface and class diagram given for EntityFramework Repository

The Base Repository class implements the interface and defines those methods to manipulate data accessibility.

public class BaseRepository<T> : IBaseRepository<T>
        where T : class
{
    private readonly IUnitOfWork _unitOfWork;
    internal DbSet<T> dbSet;
    public BaseRepository(IUnitOfWork unitOfWork)
    {
        if (unitOfWork == null) throw new ArgumentNullException("unitOfWork");
        _unitOfWork = unitOfWork;
        this.dbSet = _unitOfWork.Db.Set<T>();
    }

    /// <summary>
    /// Returns the object with the primary key specifies or throws
    /// </summary>
    /// <typeparam name="TU">The type to map the result to</typeparam>
    /// <param name="primaryKey">The primary key</param>
    /// <returns>The result mapped to the specified type</returns>
    public T Single(object primaryKey)
    {
        var dbResult = dbSet.Find(primaryKey);
        return dbResult;
    }

    public T SingleOrDefault(object primaryKey)
    {
        var dbResult = dbSet.Find(primaryKey);
        return dbResult;
    }
     
    public bool Exists(object primaryKey)
    {
        return dbSet.Find(primaryKey) == null ? false : true;
    }

    public virtual int Insert(T entity)
    {
       dynamic obj= dbSet.Add(entity);
       this._unitOfWork.Db.SaveChanges();
       return obj.Id;
    }

    public virtual void Update(T entity)
    {
        dbSet.Attach(entity);
        _unitOfWork.Db.Entry(entity).State = EntityState.Modified;
        this._unitOfWork.Db.SaveChanges();
    }

    public int Delete(T entity)
    {
        if (_unitOfWork.Db.Entry(entity).State == EntityState.Detached)
        {
            dbSet.Attach(entity);
        }
        dynamic obj=dbSet.Remove(entity);
        this._unitOfWork.Db.SaveChanges();
        return obj.Id;
    }

    public IUnitOfWork UnitOfWork { get { return _unitOfWork; } }
    internal DbContext Database { get { return _unitOfWork.Db; } }

    public Dictionary<string, string> GetAuditNames(dynamic dynamicObject)
    {
        throw new NotImplementedException();
    }

    public IEnumerable<T> GetAll()
    {
        return dbSet.AsEnumerable().ToList();
    }
    }
}

In this class, the IUnitOfWork interface is used to maintain transactions during data insertion or update.

IUnitOfWork contains two methods, Commit() and StartTransaction(), which will be implemented by the UnitOfWork class. This class will be responsible for providing the DbContext or Transaction context to start and commit the transaction.

Using the BaseRepository<T> class, you will be working with the Contact, Address entities. In EF, you will have entities according to relationships in the DB. Those entities are also called models. Sometimes the entity models are called data models. Business models and data models always need not be the same. For view purposes, a ViewModel should be used.

Now you will create two repository classes that inherit the BaseRepository class. These repository class instances will be communicating between the database layer and the business logic layer/Controller (in this example).

Let's start to create a ContactRepository...

public class ContactRepository: BaseRepository<Contact>
{
   public ContactRepository(IUnitOfWork unit):base(unit)
    {
    }
} 

Address class’ repository looks like:

public class AddressRepository : BaseRepository<Address>
{ 
  public AddressRepository(IUnitOfWork unit)
   : base(unit)
   {
   }
}

Now from the controller class, you can call the above two repository classes in the following way:

public class ContactController : Controller
{

    private IUnitOfWork uow = null;
    private ContactRepository repo = null;
    public ContactController()
    {

        uow = new UnitOfWork();
        repo = new ContactRepository(uow);
    }
    //
    // GET: /Default1/

    public ActionResult Index()
    {
        var contacts = repo.GetAll();
        return View(contacts.ToList());
    }

    //
    // GET: /Default1/Details/5

    public ActionResult Details(int id = 0)
    {
        Contact contact = repo.SingleOrDefault(id);
        if (contact == null)
        {
            return HttpNotFound();
        }
        return View(contact);
    }

    //
    // GET: /Default1/Create

    public ActionResult Create()
    {
        return View();
    }

    //
    // POST: /Default1/Create

    [HttpPost]
    public ActionResult Create(Contact contact)
    {
        if (ModelState.IsValid)
        {
            repo.Insert(contact);
            return RedirectToAction("Index");
        }

        return View(contact);
    }

    //
    // GET: /Default1/Edit/5

        public ActionResult Edit(int id = 0)
    {
        Contact contact = repo.SingleOrDefault(id);
        if (contact == null)
        {
            return HttpNotFound();
        }
        return View(contact);
    }

    //
    // POST: /Default1/Edit/5

    [HttpPost]
    public ActionResult Edit(Contact contact)
    {
        if (ModelState.IsValid)
        {
            repo.Update(contact);
            return RedirectToAction("Index");
        }
        return View(contact);
    }

    //
    // GET: /Default1/Delete/5

    public ActionResult Delete(int id = 0)
    {
        Contact contact = repo.SingleOrDefault(id);
        if (contact == null)
        {
            return HttpNotFound();
        }
        return View(contact);
    }

    //
    // POST: /Default1/Delete/5

    [HttpPost, ActionName("Delete")]
    public ActionResult DeleteConfirmed(int id)
    {
        Contact contact = repo.SingleOrDefault(id);
        
        repo.Delete(contact);
        return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing)
    {
        uow.Dispose();
        base.Dispose(disposing);
    }
}

You have to build the UnitOfWork class by implementing IUnitOfWork and this class will be responsible for creating the EF (look at the attached code). Then the repository class (ContactRepository) will be initialized with the uow object.

Look at the above controller. The related repository object and unitOfWork is created to access the database using its base class' methods.

Conclusion

Using the Repository pattern, we get the advantage of isolating the data layer from the logical layer. If the architect of an application wants to change his ORM/data storage system, then he need not worry about the business logical layer’s code. Though implementing Repository pattern is a good approach to build your application, the Repository class is a little bit slower than the direct use of a data access layer.

License

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

About the Author

Amir Hamza Md. Kayes
Software Developer (Senior)
Bangladesh Bangladesh
No Biography provided

Comments and Discussions

 
Question[My vote of 1] Rubbish. Should be called RedundantClassThatPretendsToDoWorkButDoesNothing Pinmembermikebridge24-Apr-14 12:08 
GeneralWell-written PinmemberMember 1011881429-Mar-14 7:27 
GeneralMy vote of 3 Pinmemberhirikarate2-Mar-14 16:20 
QuestionNonsense PinmemberPiotr Perak27-Jan-14 11:34 
Suggestionmodify if you want and then use... PinprofessionalAmir Hamza Md. Kayes29-Jan-14 8:33 
AnswerRe: Nonsense PinmemberNoni Gowdah29-Jan-14 9:09 
GeneralRe: Nonsense [modified] PinmemberPiotr Perak2-Feb-14 7:33 
GeneralMy vote of 1 Pinmemberarpitk16-Jan-14 0:54 
AnswerRe: My vote of 1 PinprofessionalAmir Hamza Md. Kayes17-Jan-14 9:21 
SuggestionYou haven't accomplished abstraction Pinmembersweeperq9-Jan-14 16:26 
SuggestionScript is not complete PinmemberThurupathan5-Jan-14 4:18 
Bug[My vote of 2] Repository done ok but not have Unit Of Work correct PinmemberHarsh Baid15-Dec-13 8:27 
Generalvote PinmemberMember 1025970510-Dec-13 17:23 
Questionvite PinmemberMember 1025970510-Dec-13 17:22 
GeneralMy vote of 5 PinprofessionalS. M. Ahasan Habib9-Dec-13 17:55 
GeneralRe: My vote of 5 PinprofessionalAmir Hamza Md. Kayes9-Dec-13 21:46 
QuestionMy Vote of 5 Pinmemberrubol5-Dec-13 22:04 
GeneralGreat PinmemberMember 81206972-Dec-13 15:22 
GeneralMy vote of 2 PinmemberMember 39723782-Dec-13 9:46 
QuestionStrongly coupled unit of work [modified] PinmemberJeremy Todd2-Dec-13 8:39 
AnswerRe: Strongly coupled unit of work PinprofessionalS. M. Ahasan Habib10-Dec-13 20:52 
GeneralRe: Strongly coupled unit of work PinmemberJeremy Todd10-Dec-13 20:55 
GeneralMy vote of 5 PinmemberHumayun Kabir Mamun1-Dec-13 19:01 
QuestionGreat..! PinmemberRiazul Islam Mazumder1-Dec-13 19:00 
QuestionVery nice. But one question Pinmemberednrg29-Nov-13 9:37 
GeneralMy vote of 5 PinmemberM Rayhan28-Nov-13 19:39 
SuggestionMy vote of 5 PinmvpRahul Rajat Singh28-Nov-13 17:08 
AnswerRe: My vote of 5 PinprofessionalAmir Hamza Md. Kayes29-Nov-13 8:35 
QuestionNice post PinmemberShahinur Kabir28-Nov-13 16:48 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 10 Dec 2013
Article Copyright 2013 by Amir Hamza Md. Kayes
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid