Unit Of Work ile Generic Repository Tasarım Deseni

IRepository : Ortak olarak tanımlanacak repository metotlarını içerir. Get(id),GetAll(),Add(Entity),Remove(id)
Repository : İnterfacede tanımlanan metotları doldurur.
IDepartmentRepository : Eğer özel tanımlamamız gereken ekstra özel metotlar olursa kullanacağımız interface. IRepositoryden kalıtılmalı.
DepartmentRepository :  İnterfacede tanımlanan metotları doldurur.

IUnitOfWork ve UnitOfWork : tüm repositoryler toplanır ve saveChanges burada olur.

1.Modeller

 public class Department
 {
    public Department()
    {
     personels = new List<Personel>();
    }
     public int Id{get; set;}
     public int Name{get; set;} 

   public ICollection<Personel> personels{get; set;}
 }

 public class Personel
 {
     public int Id{get; set;}
     public int Name{get; set;}
     public string LastName{get; set;}
     public int DepartmentId{get; set;}

    public Department Department{get; set;}  
 }

public class PersonnelContext : DbContext
 {
     public PersonnelContext() : base("")
     { 
     }
      public DbSet<Department> Departments {get; set;}
      public DbSet<Personel> Personnels {get; set;}
 }

2.Repositoryler

public interface IRepository<TEntity> : class   //interface jeneriktir yani ne geleceğini bilemeyiz. Runtimeda belirlenir. Ama bildiğimiz tek şey TEntity kesinlikle bir class.
 {
     TEntity  GetById(int id);
     IEnumerable<TEntity>   GetAll();
      void  Add(TEntity entity);
      void AddRange(IEnumerable<TEntity> entities);
      void Remove(int id);
      void   RemoveRange(IEnumerable<TEntity> entities);
 }

class Repository<TEntity> : IRepository<TEntity> where TEntity : class //sana TEntity tipinde birşey gelecek ama ne geleceğini ben de bilmiyorum.
{
     protected DbContext _context;
     private DbSet<TEntity> _dbset;

     public Repository(DbContext context)  //repositoryi kullanmak isteyen buna bir defa dbcontext vermek zorunda
     {  _context = context; 
         _dbSet = _context.Set<TEntity>(); 

     }
   
      public void Add(TEntity entity)
      {
           //_context.Departments.Add(entity);
            //  _context.Set<TEntity>.Add(entity);
             _dbSet.Add(entity);
      }

     public void AddRange(IEnumerable<TEntity> entities)
     {
         // _context.Set<TEntity>.AddRange(entitites);
           _dbSet.AddRange(entities);
     }

     public IEnumerable<TEntity> GetAll()
     {
         return _dbSet.toList();
     }

     public TEntity GetById(int id)
     {
       return _dbSet.Find(id);
     }
    
     public void Remove(int id)
     {
      _dbSet.Remove(GetById(id));
     }

     public void RemoveRabge(IEnumerable<TEntity> entities)
     {
      _dbSet.RemoveRange(entities);
     }
}

Departmanlara özgü işlemlerin var ise

 public interface IDepartmentRepository : IRepository<Department//departmana özgü olduğundan tip gönderebildik.
   {
             IEnumerable<Department>  GetTopDepartments(int count);
             IEnumareble<Department>   GetDepartmentsWithPersonnels();
   }

  public class DepartmentRepository : Repository<Department> , IDepartmentRepository
  { 
       public DepartmnetRepository (PersonnelContext context) : base(context)
       {
       }

       public IEnumerable<Department> GetDepartmentsWithPersonels()
       {
        return PersonnelContext.Departments.Include("Personnels").ToList();
       }

       public IEnumerable<Department> GetTopDepartments(int count)
       {
         return PersonnelContext.Departments.Take(count);
       }

       public PersonnelContext PersonnelContext {get{return _context as PersonnelContext} } //bu cast işlemine sürekli ihtiyac duyacağız.
  }
  
   public interface IPersonnelRepository : IRepository<Personnel>
   {
     IEnumerable<Personnel> GetPersonnelsWithDepartments();
   }
  
    public class PersonnelRepository : Repository<Personnel> , IPersonnelRepository
    {
       public PersonnelRepository(PersonnelContext context) : base(context) //sen personelRepositoryi kullanmak istiyorsan önce personelContext vermek zorundasın. 
       {}   
    
       public IEnumerable<Personnel> GetPersonnelsWithDepartments()
       {
          return PersonnelContext.Personnels.Include("Department").ToList();
       }   
       public PersonnelContext PersonnelContext {get{return _context}} 
    }


 

3. Unit Of Work Kısmı : tüm repositoryler burada toplanır.

 public interface IUnitOfWork : IDisposable
 {
     IDepartmentRepository DepartmentRepository{get;}
     IPersonnelRepository  PersonelRepository{get;}

     int Complete();

 }

 public class UnitOfWork : IUnitOfWork
 {
       private PersonnelContext _personnelContext;
   
        public UnitOfWork(PersonnelContext context)
        {
          _personnelContext = context;
           DepartmentRepository = new DepartmentRepository(_personnelContext);
           PersonnelRepository  = new PersonnelRepository (_personnelContext);
        }

        public IDepartmentRepository DepartmentRepository {get; private set; }
        public IPersonnelRepository  PersonnelRepository {get; private set;}

        public int Complete()
        {
            return  _personnelContext.SaveChanges();
        }

       public void Dipsose()
       {
         _personnelContext.Dispose(); 
       }
 }

**************************************************************************

4. Console UI Kısmı

  static void Main(string[] args)
  {
        UnitOfWork unitOfWork = new UnitOfWork(new PersonnelContext());

        //tüm repositoryler tek bir classtan gelir.
        unitOfWork.DepartmentRepository --> hem ortak hem deparmana özgü metotlar
        unitOfWork.PersonnelRepository   --> aynı şekilde

        unitOfWork.DepartmentRepository.Add(new Department{.........}) --> veri tabanına değil rama ekleme
        unitOfWork.PazarlamaRepository.Add(new Department{.........}) --> veri tabanına değil rama ekleme
        unitOfWork.Complete();  ---> tamamlama .. iki kayıt tek transaction üzerinden eklendi.
  }