存储库模式工作单元依赖注入Ninject

时间:2016-04-01 12:14:02

标签: c# dependency-injection ninject repository-pattern unit-of-work

我在我的架构中使用了存储库,工作单元和依赖注入模式 我的等级:

核心

数据层

BusinessLayer

ServiceLayer

我的结构有问题,如上所述的工作单位

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

这里我想注入像_kullaniciDAL

这样的DataAccessLayers

搜索了很多,我看到了一些通用生成存储库的例子我不想直接从业务访问存储库实例,我想访问我的KullaniciDal类的实例 这是KullaniciDal的代码

 public interface IKullaniciDal : IRepositoryEntityFramework<Kullanici>
{
}

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

我想为一些特殊的数据访问层编写一些额外的函数,并希望将这些实例用作工作单元类的一部分

我如何注入Dal课程? 小心我将上下文对象传递给每个dal类

2 个答案:

答案 0 :(得分:1)

我在这里看到了几个问题。

首先,您的UoW正在新建DAL,而不是通过DI注入它。如果你正在进行DI路线,那么最好让DI注入所有东西并让它自己管理对象的范围。作为一般规则,如果您发现自己将new()与基础结构类一起使用,请退后一步并考虑注入它。

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

下一个问题更多的是设计问题。为什么UoW需要所有这些DAL?我自己发现这很奇怪。

如果我实现了一个需要控制UoW和DAL的业务层,我只需将它们注入业务层。

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
    }

}

在使用诸如EF的ORM时,存储库/ dll和工作单元都需要Context,但它们是单独的模式。我允许你的DI容器适当地调整你的上下文,你的UoW,你的BLL等,你不需要担心传递依赖关系,让容器为你工作。

这也有其他SOLID设计优势。考虑一下你是否正在实现一个自动提交你的uow与http会话的http过滤器。过滤器只需要知道IUnitOfWork方法提交,回滚等。它应该依赖于最小接口,它不需要知道DAL。

答案 1 :(得分:0)

我找到了另一种在需要时动态创建存储库的解决方案。 它还支持多个数据上下文,还有一点是IUnitOfWork接口继承了IDisposable。该代码适用于EF Core v2.0。这是所有UnitOfWork.cs类代码:

public class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext
{
    private Dictionary<string, dynamic> _repositories;
    private DbContext _context;

    public UnitOfWork(TContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public IRepository<TEntity> Repository<TEntity>() where TEntity : class, IEntity, new()
    {
        if (_repositories == null)
        {
            _repositories = new Dictionary<string, dynamic>();
        }
        var type = typeof(TEntity).Name;
        if (_repositories.ContainsKey(type))
        {
            return (IRepository<TEntity>)_repositories[type];
        }
        _repositories.Add(type, Activator.CreateInstance(typeof(RepositoryEntityFramework<TEntity>), _context));
        return _repositories[type];
    }

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

    public void BeginTransaction(System.Data.IsolationLevel isolationLevel = System.Data.IsolationLevel.ReadCommitted)
    {
        _context.Database.BeginTransaction();
    }

    public bool Commit()
    {
        _context.Database.CommitTransaction();
        return true;
    }

    public void Rollback()
    {
        _context.Database.RollbackTransaction();
    }

    /// <inheritdoc />
    /// <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 (_context != null)
            {
                _context.Dispose();
                _context = null;
            }
        }
    }
}