Unıt Of Work Design Pattern

Kısaca açıklamak gerekirse bu pattern iş katmanında yapılan her değişikliğin anlık olarak database yansıması yerine tek bir kanaldan(tek bir transaction) toplu halde gerçekleşmesini sağlar.

Temel Olarak; 1- CRUD işlemleri yapıldığı sınıflara UnitOfWork içerisinden "DbContext" verilmeli 2- CRUD işlemini yapan sınıf kaydetme işlemlerini DBContext ‘in SubmitChanges() metodunu çağırmamalı onun yerine işlemle UnitOfWork sınıfına yazılmış Save() metodu çağırmalı. Yani tüm işlemleri UnitOfWorke yapacağımızdan save işlemi de UnitOfWorkte bulunmalı. 3- İşlemleri veri tabanına aktarma sırasında hata ile karşılaşıldığında Rollback işlemleri için metot yazılmalı.

Örnek : ATM den para çekme işleminde tüm veriler girip okey tuşuna basıldığında normal şartlarda biz hesabımızdan girdiğimiz para miktarı kadar çekilmesine izin vermiş olduk. Fakat hesabımızda bu kadar para yoksa verdiğimiz onay ne işe yarayacak sorusunun cevabını UnitOFWORK verir. UnitOfWork ile birlikte bu örnekteki bütün işlemler bittikten sonra ya işlem yapılır yada RollBack methodları çalışır. Böylece hesabımızda para varsa para çekmiş oluruz yoksa işlem sırasında girdiğimiz bütün veriler iptal edilir.

Avantajları 1- Veri iletişimini tek kanaldan sağlamak. 2- Veritabanıyla alakalı bir problem meydana gelirse nereye bakmamız gerektiğini biliyor oluruz. 3- Kod tekrarının önüne geçip tekrar tekrar ihtiyaç duyulabilecek sorguları metoda bağlamak. 4- İleride Entity Frameworkten vazgeçip yerine bir ORM kullanacağımızı varsayalım tek dokunmamız gereken kısım DAL olacaktır.

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- Repository​

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

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

     public void AddRange(IEnumerable<TEntity> entities)
     {
         // _context.Set.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);
     }
}

3- 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}} 
    }

4- Unit Of Work Kısmı : Tüm Repository'ler 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(); 
       }
 }

5. 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.
  }

https://hakantopuz.medium.com/unit-of-work-design-pattern-nedir-nas%C4%B1l-kullan%C4%B1l%C4%B1r-6177802b693

Last updated

Was this helpful?