Generics Repository with Unit of work c#

Before dive into above topics i.e. Generics Repository with Unit of work in c#, we need to learn basic and fundamental concepts as following

  1. What is Repository Pattern?

Repository pattern is an abstraction layer between your business layer and data layer.So, there is no direct connection between business layer and data layer. It is also called as Loose Coupling. So we can change data layer code logic whenever there is need.

  1. What is Repository?

A Repository is nothing but a class defined per entity, with all the operations possible on that specific entity. For example, a repository for an entity Customer will have basic CRUD operations and any other possible operations related to it.

  1. What is Generic Repository?

A generic repository is the one that can be used for all the entities, in other words it can be either used for Order or Customer or any other entity.

 

  1. Unit of Work pattern?

Unit of Work pattern is nothing but we create single instance of dbcontext for multiple database transactions and call SaveChanges() of dbcontext class Method  in the last. So we maintain our database integrity. I.e. either all changes committed to database or nothing in case of any failure.

before moving further, i feel you must have basic knowledge of

  1. Entity Framework
  2. Generic Type Constraints (you can refer my WordPress Post link too)

 

Now let’s understand above concept with sample example.

STEP  1.  Create two entities i.e. Student and Standard

// Standard Entity

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace EntityFramework_CF
{
    public class Standard
    {
        public Standard()
        {
        }
        public int StandardId { get; set; }
        [Required]
        public string StandardName { get; set; }
        //Kindly note that,above StandardName is mandatory column
        public ICollection<Student> Students { get; set; }
    }
}

 

// Student Entity

using System;
namespace EntityFramework_CF
{
    public class Student
    {
        public Student()
        {
        }
        public int StudentID { get; set; }
        public string StudentName { get; set; }
        public DateTime? DateOfBirth { get; set; }
        public byte[] Photo { get; set; }
        public decimal Height { get; set; }
        public float Weight { get; set; }
        public Standard Standard { get; set; }
    }
}

 

//So far so good (at least i feel :), now let’s write remaining code in single console application

using System;
using System.Data.Entity;
namespace EntityFramework_CF
{
    class Program
    {
        static void Main(string[] args)
        {
            GenericUnitOfWork _UOW = new GenericUnitOfWork();
            Student student = new Student() { StudentName = "vishal kadam" };
            _UOW.GetRepoInstance<Student>().Save(student);
 
            Standard standard = new Standard()
            {
                StandardId = 1
            };
            _UOW.GetRepoInstance<Standard>().Save(standard);
            _UOW.SaveChanges();
            _UOW.Dispose();
        }
    }
    public class SchoolContext : DbContext
    {
        public SchoolContext()
            : base("name=DBConnection1")
        {
 
        }
        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            Database.SetInitializer<SchoolContext>(null);
            base.OnModelCreating(modelBuilder);
        }
    }
 
    public interface IRepository<TEntity> where TEntity : class
    {
        TEntity Get(int id);
        void Save(TEntity entity);
    }
    public class GenricRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        DbSet<TEntity> _dbset;
        private SchoolContext _dbcontext;
        public GenricRepository(SchoolContext dbcontext)
        {
            _dbcontext = dbcontext;
            _dbset = _dbcontext.Set<TEntity>();
        }
 
        public TEntity Get(int id)
        {
            return _dbset.Find(id);
        }
 
        public void Save(TEntity Entity)
        {
            _dbset.Add(Entity);
        }
 
    }
 
    public interface IUnitOfWork : IDisposable
    {
        int SaveChanges();
    }
 
    public class GenericUnitOfWork : IUnitOfWork
    {
        private SchoolContext _dbcontext = new SchoolContext();
 
        public GenricRepository<T> GetRepoInstance<T>() where T : class
        {
            return new GenricRepository<T>(_dbcontext);
        }
        public int SaveChanges()
        {
            return _dbcontext.SaveChanges();
        }
 
 
 
        /// <summary>
        /// Disposes the current object
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        /// <summary>
        /// Disposes all external resources.
        /// </summary>
        /// <param name="disposing">The dispose indicator.</param>
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_dbcontext != null)
                {
                    _dbcontext.Dispose();
                    _dbcontext = null;
                }
            }
        }
    }
}

 

Now let’s decode above Sample Code

  1. We define one interface with name IRepository.
public interface IRepository<TEntity> where TEntity : class
    {
        TEntity Get(int id);
        void Save(TEntity entity);
    }

This is our base interface.

  1. We define Generic Repository class with name GenricRepository which implements interface IRepository as mentioned in step 1.This class common for all Entities with Get and Save operation implemented into it (You can implement all or which is required).
public class GenricRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        DbSet<TEntity> _dbset;
        private SchoolContext _dbcontext;
        public GenricRepository(SchoolContext dbcontext)
        {
            _dbcontext = dbcontext;
            _dbset = _dbcontext.Set<TEntity>();
        }
 
        public TEntity Get(int id)
        {
            return _dbset.Find(id);
        }
 
        public void Save(TEntity Entity)
        {
            _dbset.Add(Entity);
        }
 
    }
  1. We define our UnitOfWork class with name GenericUnitOfWork as following
    public interface IUnitOfWork : IDisposable
    {
        int SaveChanges();
    }
 
    public class GenericUnitOfWork : IUnitOfWork
    {
        private SchoolContext _dbcontext = new SchoolContext();
 
        public GenricRepository<T> GetRepoInstance<T>() where T : class
        {
            return new GenricRepository<T>(_dbcontext);
        }
        public int SaveChanges()
        {
            return _dbcontext.SaveChanges();
        }
 
 
 
        /// <summary>
        /// Disposes the current object
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        /// <summary>
        /// Disposes all external resources.
        /// </summary>
        /// <param name="disposing">The dispose indicator.</param>
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_dbcontext != null)
                {
                    _dbcontext.Dispose();
                    _dbcontext = null;
                }
            }
        }
    }
  1. Now look at the following code
            GenericUnitOfWork _UOW = new GenericUnitOfWork();
            Student student = new Student() { StudentName = "vishal kadam" };
            _UOW.GetRepoInstance<Student>().Save(student);
            Standard standard = new Standard()
            {
                StandardId = 1
            };
          //here we will get error because we are not save value for column StandardName 
         // which is mandatory column
            _UOW.GetRepoInstance<Standard>().Save(standard);
            _UOW.SaveChanges();
            _UOW.Dispose();

As you see that , StandardName column in required field in Standard Entity which we are not provided.So save operation for Student entity run successfully. But in case of Standard Entity, it fails.

  1. Here UnitOfWork pattern comes in rescue to us. since we use one instance of dbcontext for both database operation. So,SaveChanges() method not executed  and above changes are not saved in database.

6. If we change above code as following ,

            GenericUnitOfWork _UOW = new GenericUnitOfWork();
            Student student = new Student() { StudentName = "vishal kadam" };
            _UOW.GetRepoInstance<Student>().Save(student);
            Standard standard = new Standard()
            {
                StandardId = 1,
                StandardName = "First"
            };
            _UOW.GetRepoInstance<Standard>().Save(standard);
            _UOW.SaveChanges();
            _UOW.Dispose();

Since, no validation rule is broken. SaveChanges method called and all database changes are saved successfully..

Thanks for reading.

Any suggestion would be truly appreciated.

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s