Search code examples
c#dependency-injectionninjectrepository-patternunit-of-work

Repository Pattern Unit of work Dependency Injection Ninject


I use repository, unit of work and dependency injection patterns in my architecture My tiers :

Core

DataLayer

BusinessLayer

ServiceLayer

There is something wrong in my structure, in unit of work class as above

   public class UnitOfWork:IUnitOfWork
{
    private readonly IDataContext _context;
    private IKullaniciDal _kullaniciDal;
    private IKategoriDal _kategoriDal;
    private IUrunDal _urunDal;
    public UnitOfWork(IDataContext context)
    {
        _context = context;
    }

    public IKategoriDal KategoriDal => _kategoriDal ?? (_kategoriDal = new KategoriDal(_context));

    public IKullaniciDal KullaniciDal => _kullaniciDal ?? (_kullaniciDal =  new KullaniciDal(_context));

    public IUrunDal UrunDal => _urunDal ?? (_urunDal = new UrunDal(_context));

    public void SaveChanges()
    {
        _context.SaveChanges();
    }
}

here i want to inject DataAccessLayers like _kullaniciDAL

searched a lot and i saw some examples for generating repository genericly bu i dont want to access the repository instance directly from business, i want to access the instances of my KullaniciDal class Here is the code of KullaniciDal

 public interface IKullaniciDal : IRepositoryEntityFramework<Kullanici>
{
}

public class KullaniciDal : RepositoryEntityFramework<Kullanici>, IKullaniciDal
{
    public KullaniciDal(IDataContext dbContextBase) : base(dbContextBase)
   {
   }
}

I want to write some extra functions to data access layer in special to some of them and want to use the instances as a part of unit of work class

How can i inject Dal classes? Be carefull that i pass context object to every dal class


Solution

  • There's a couple issues I see here.

    First, your UoW is newing up the DAL itself rather than having it injected by DI. If you're going the DI route you're better off just letting the DI inject everything and let it manage the scope of the objects etc by itself. As sort of a general rule, if you find yourself using new() with an infrastructure class, take a step back and consider injecting it.

    public class UnitOfWork:IUnitOfWork
    {
        private readonly IDataContext _context;
        public UnitOfWork(IDataContext context,IKullaniciDal kullaniciDal,IKategoriDal kategoriDal, IUrunDal urunDal)
        {
            KullaniciDal = kullaniciDal;
            KategoriDal = kategoriDal;
            UrunDal = urunDal;
            _context = context;
        }
    
        public IKategoriDal KategoriDal{get;private set;}
    
        public IKullaniciDal KullaniciDal{get;private set;}
    
        public IUrunDal UrunDal{get;private set;}
    
        public void SaveChanges()
        {
            _context.SaveChanges();
        }
    }
    

    The next question is more of a design question. Why are all of these DALs needed by the UoW? I find this odd myself.

    If I was implementing a business layer that needed to control the UoW and a DAL, I would simply inject them into the business layer.

    public class FooBLL
    {
        private IKullanicDal _kullanicDal;
        private IUnitOfWork _unitOfWork;
        public FooBLL(IKullanicDal kullanicDal,IUnitOfWork unitOfWork)
        {
            _kullanicDal = kullanicDal;
            _unitOfWork = unitOfWork;
        }
    
        public void FooBusinessMethod()
        {
          _unitOfWork.Begin();
          //do something with dal
          //_unitOfWork.Commit etc
        }
    
    }
    

    It's true that the Context is required by both the repository/dll and the unit of work when using an ORM such as EF, but they are seperate patterns. I would allow your DI container to scope both your context, your UoW, your BLL etc all appropriately and you won't need to worry about passing dependencies around, let the container do the work for you.

    This has other SOLID design benefits as well. Consider if you are implementing say an http filter that auto-commits your uow with the http session. The filter only needs to know about the IUnitOfWork methods commit, rollback etc. It should depend on that minimum interface, it doesn't need to know about the DALs.