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

Repository Pattern Unit of work Dependency Injection Ninject

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

核心

数据层

业务层

服务层

我的结构有问题,在工作单元中 class 如上所述

   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 的实例 class 这是 KullaniciDal

的代码
 public interface IKullaniciDal : IRepositoryEntityFramework<Kullanici>
{
}

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

我想为数据访问层编写一些额外的功能,特别是其中一些功能,并希望将这些实例用作工作单元的一部分 class

我如何注射 Dal classes? 小心我将上下文对象传递给每个 dal class

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

首先,您的 UoW 正在更新 DAL 本身,而不是由 DI 注入它。如果您要走 DI 路线,最好让 DI 注入所有内容并让它自己管理对象的范围等。作为一般规则,如果您发现自己将 new() 与基础设施一起使用 class,请退后一步并考虑注入它。

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 时,repository/dll 和工作单元都需要上下文,但它们是不同的模式。我将允许您的 DI 容器适当地确定您的上下文、您的 UoW、您的 BLL 等的范围,并且您无需担心传递依赖项,让容器为您完成工作。

这还有其他 SOLID 设计优势。考虑一下您是否正在实施一个 http 过滤器,该过滤器会自动将您的 uow 提交给 http 会话。过滤器只需要了解 IUnitOfWork 方法提交、回滚等。它应该依赖于最小接口,不需要了解 DAL。

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

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