This article shows you how to use Repository and Unit Of Work patterns with Entity Framework in ASP.NET MVC using c# code.

Repository is a pattern used to create an intermediate abstraction layer between data layer and business class. This class contains an operation method that communicates with the data class to serve the business from the logical class. The purpose is to create this class to isolate the data access so that changes do not directly affect the business logic layer.

Unit of work is a pattern that handles transactions during data manipulation using the Repository pattern.

Repository Pattern and Unit of Work using Entity Framework

Object-relational mapping (ORM) is a programming technique to convert data between types that are not compatible with the object-oriented programming language. We can treat objects / models as objects in the database. We can write code / query on the object model to retrieve data.

Advantages of ORM

  • You can manipulate data (CRUD) to be processed without writing SQL queries
  • Data mapping between result set and entity is the main function of ORM
  • Use Unit of work / Context to handle transactions during data manipulation.
  • Write a model in a separate place for model management in the database.
  • Programmers can program object-oriented completely when doing any action with business class and data.

Entity framework

It helps map to database objects. This framework helps write POCO and creates database and it can also create model from existing database.

You can write different repository classes for each entity. But for database actions some common methods will be used for CRUD actions. So using different repositories will create redundant code. That's why you should use a common repository.

To practice the demo, you should create a diagram database as the following.

unit of work

Next, Add an ADO.NET Entity Data Model to your project, then select all the tables that you want to add into your data model.

entity framework

Add classes as the following diagram to your project.

entity framework c#

The BaseRepository class implements the interface and defines the methods for manipulating data.

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>();
    }

    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 while adding new or updated data.

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

Using the BaseRepository <T> class you will work with Contact, Address model. In EF, you have models equivalent to the models that are tables in the database.

Now you will create two repository classes that inherit the BaseRepository class. For example, this repository class will communicate between database class and business class.

ContactRepository.cs

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

AddressRepository.cs

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

To use UnitOfWork and Repositoty patterns in asp.net mvc you can write your code as shown below.

public class ContactController : Controller
{

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

        uow = new UnitOfWork();
        repo = new ContactRepository(uow);
    }

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

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

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

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

        return View(contact);
    }

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


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

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


    [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);
    }
}