Click here to Skip to main content
11,635,098 members (76,047 online)
Click here to Skip to main content

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

, 10 Dec 2013 CPOL 140.5K 8.3K 110
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)

Share

About the Author

Amir Hamza Md. Kayes
Technical Lead
Bangladesh Bangladesh
No Biography provided

You may also be interested in...

Comments and Discussions

 
Questionare you by chance Rahul Rajat Singh butt buddy Pin
Member 1177111116-Jun-15 15:14
memberMember 1177111116-Jun-15 15:14 
SuggestionThere is another article about UnitOfWork with EntityFramework . Pin
huoxudong12514-May-15 15:16
memberhuoxudong12514-May-15 15:16 
GeneralNo details specified. Pin
Shalu34517-Apr-15 4:19
memberShalu34517-Apr-15 4:19 
GeneralMy vote of 1 Pin
U-Pretti20-Feb-15 10:20
memberU-Pretti20-Feb-15 10:20 
BugIncorrect "Picture #2" - Then add another project to solution for data access named Contact.Repository. Pin
Member 81519511-Jan-15 4:11
memberMember 81519511-Jan-15 4:11 
GeneralMy vote of 1 Pin
Aurimas14-Nov-14 9:38
memberAurimas14-Nov-14 9:38 
GeneralMy vote of 1 Pin
Seany8411-Oct-14 10:39
memberSeany8411-Oct-14 10:39 
Question[My vote of 1] Rubbish. Should be called RedundantClassThatPretendsToDoWorkButDoesNothing Pin
mikebridge24-Apr-14 12:08
membermikebridge24-Apr-14 12:08 
AnswerRe: [My vote of 1] Rubbish. Should be called RedundantClassThatPretendsToDoWorkButDoesNothing Pin
AFMatambo23-Oct-14 17:34
memberAFMatambo23-Oct-14 17:34 
AnswerRe: [My vote of 1] Rubbish. Should be called RedundantClassThatPretendsToDoWorkButDoesNothing Pin
Aurimas21-Nov-14 6:06
memberAurimas21-Nov-14 6:06 
SuggestionRe: [My vote of 1] Rubbish. Should be called RedundantClassThatPretendsToDoWorkButDoesNothing Pin
Member 141634621-May-15 4:26
memberMember 141634621-May-15 4:26 
GeneralWell-written Pin
Member 1011881429-Mar-14 7:27
memberMember 1011881429-Mar-14 7:27 
GeneralMy vote of 3 Pin
hirikarate2-Mar-14 16:20
memberhirikarate2-Mar-14 16:20 
QuestionNonsense Pin
Piotr Perak27-Jan-14 11:34
memberPiotr Perak27-Jan-14 11:34 
Suggestionmodify if you want and then use... Pin
Amir Hamza Md. Kayes29-Jan-14 8:33
professionalAmir Hamza Md. Kayes29-Jan-14 8:33 
AnswerRe: Nonsense Pin
Noni Gowdah29-Jan-14 9:09
memberNoni Gowdah29-Jan-14 9:09 
GeneralRe: Nonsense Pin
Piotr Perak2-Feb-14 7:33
memberPiotr Perak2-Feb-14 7:33 
GeneralMy vote of 1 Pin
arpitk16-Jan-14 0:54
memberarpitk16-Jan-14 0:54 
AnswerRe: My vote of 1 Pin
Amir Hamza Md. Kayes17-Jan-14 9:21
professionalAmir Hamza Md. Kayes17-Jan-14 9:21 
SuggestionYou haven't accomplished abstraction Pin
sweeperq9-Jan-14 16:26
membersweeperq9-Jan-14 16:26 
SuggestionScript is not complete Pin
Thurupathan5-Jan-14 4:18
memberThurupathan5-Jan-14 4:18 
Bug[My vote of 2] Repository done ok but not have Unit Of Work correct Pin
Harsh Baid15-Dec-13 8:27
memberHarsh Baid15-Dec-13 8:27 
Generalvote Pin
Member 1025970510-Dec-13 17:23
memberMember 1025970510-Dec-13 17:23 
Questionvite Pin
Member 1025970510-Dec-13 17:22
memberMember 1025970510-Dec-13 17:22 
GeneralMy vote of 5 Pin
S. M. Ahasan Habib9-Dec-13 17:55
professionalS. M. Ahasan Habib9-Dec-13 17:55 
GeneralRe: My vote of 5 Pin
Amir Hamza Md. Kayes9-Dec-13 21:46
professionalAmir Hamza Md. Kayes9-Dec-13 21:46 
QuestionMy Vote of 5 Pin
rubol5-Dec-13 22:04
memberrubol5-Dec-13 22:04 
GeneralGreat Pin
Member 81206972-Dec-13 15:22
memberMember 81206972-Dec-13 15:22 
GeneralMy vote of 2 Pin
Member 39723782-Dec-13 9:46
memberMember 39723782-Dec-13 9:46 
QuestionStrongly coupled unit of work Pin
Jeremy Todd2-Dec-13 8:39
memberJeremy Todd2-Dec-13 8:39 
AnswerRe: Strongly coupled unit of work Pin
S. M. Ahasan Habib10-Dec-13 20:52
professionalS. M. Ahasan Habib10-Dec-13 20:52 
GeneralRe: Strongly coupled unit of work Pin
Jeremy Todd10-Dec-13 20:55
memberJeremy Todd10-Dec-13 20:55 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun1-Dec-13 19:01
memberHumayun Kabir Mamun1-Dec-13 19:01 
QuestionGreat..! Pin
Riazul Islam Mazumder1-Dec-13 19:00
memberRiazul Islam Mazumder1-Dec-13 19:00 
QuestionVery nice. But one question Pin
ednrg29-Nov-13 9:37
memberednrg29-Nov-13 9:37 
GeneralMy vote of 5 Pin
M Rayhan28-Nov-13 19:39
memberM Rayhan28-Nov-13 19:39 
SuggestionMy vote of 5 Pin
Rahul Rajat Singh28-Nov-13 17:08
mvpRahul Rajat Singh28-Nov-13 17:08 
AnswerRe: My vote of 5 Pin
Amir Hamza Md. Kayes29-Nov-13 8:35
professionalAmir Hamza Md. Kayes29-Nov-13 8:35 
QuestionNice post Pin
Shahinur Kabir28-Nov-13 16:48
memberShahinur 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 | Terms of Use | Mobile
Web04 | 2.8.150728.1 | Last Updated 10 Dec 2013
Article Copyright 2013 by Amir Hamza Md. Kayes
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid