以使用知识库的工作模式为单位进行dependency injection

我想要创build一个工作单元类,以类似的方式围绕存储库。

我遇到的问题是试图通过用IRepository接口replace示例中的通用存储库来实现dependency injection。 在链接文章中的uow中,他们使用getter来检查版本库是否被实例化,如果没有,则实例化它。

public GenericRepository<Department> DepartmentRepository { get { if (this.departmentRepository == null) { this.departmentRepository = new GenericRepository<Department>(context); } return departmentRepository; } } 

这是强烈耦合。

我可以看到两个方面。

  1. 使用构造函数注入。
  2. 使用setter注射。

1的问题是,如果我注入所有的存储库,我不得不实例化每个存储库,即使我没有在特定的工作单元中使用它们。 因此招致这样做的开销。 我想象的是使用一个数据库范围内的工作单元,所以这会导致大量的不必要的实例化和巨大的构造函数。

2的问题是很容易忘记设置和结束空参考例外。

在这种情况下是否有任何的最佳做法? 还有其他的select我错过了吗?

我只是进入dependency injection,并已经做了所有的研究,我可以find关于这个话题,但我可能会失去一些关键。

解决这个问题的方法是不要让UnitOfWork负责通过Container注入来创build每个Repository ,而是让每个Repository负责确保UnitOfWork在实例化时知道它的存在。

这将确保

  • 您的UnitOfWork不需要为每个新版本Repository进行更改
  • 你没有使用服务定位器(被许多人认为是反模式 )

这是最好的演示与一些代码 – 我使用SimpleInjector所以例子是基于这个:

Repository抽象开始:

 public interface IRepository { void Submit(); } public interface IRepository<T> :IRepository where T : class { } public abstract class GenericRepository<T> : IRepository<T> where T : class { } 

UnitOfWork

 public interface IUnitOfWork { void Register(IRepository repository); void Commit(); } 

每个Repository 必须注册自己的UnitOfWork ,这可以通过更改抽象的父类GenericRepository以确保完成:

 public abstract class GenericRepository<T> : IRepository<T> where T : class { public GenericRepository(IUnitOfWork unitOfWork) { unitOfWork.Register(this); } } 

每个真正的RepositoryGenericRepositoryinheritance:

 public class Department { } public class Student { } public class DepartmentRepository : GenericRepository<Department> { public DepartmentRepository(IUnitOfWork unitOfWork): base(unitOfWork) { } } public class StudentRepository : GenericRepository<Student> { public StudentRepository(IUnitOfWork unitOfWork) : base(unitOfWork) { } } 

joinUnitOfWork的物理实现,你就可以设置:

 public class UnitOfWork : IUnitOfWork { private readonly Dictionary<string, IRepository> _repositories; public UnitOfWork() { _repositories = new Dictionary<string, IRepository>(); } public void Register(IRepository repository) { _repositories.Add(repository.GetType().Name, repository); } public void Commit() { _repositories.ToList().ForEach(x => x.Value.Submit()); } } 

容器注册可以设置为自动提取IRepository所有已定义实例,并为其注册一个生命周期范围,以确保它们在您的事务的整个生命周期中都能够存活:

 public static class BootStrapper { public static void Configure(Container container) { var lifetimeScope = new LifetimeScopeLifestyle(); container.Register<IUnitOfWork, UnitOfWork>(lifetimeScope); container.RegisterManyForOpenGeneric( typeof(IRepository<>), lifetimeScope, typeof(IRepository<>).Assembly); } } 

通过这些抽象和围绕DI构build的体系结构,您可以获得一个UnitOfWork ,它知道在任何服务调用中已经实例化的所有Repository ,并且您有编译时validation所有的存储库已经定义。 你的代码是可以打开的,但是可以修改 。

要testing所有这些 – 添加这些类

 public class SomeActivity { public SomeActivity(IRepository<Department> departments) { } } public class MainActivity { private readonly IUnitOfWork _unitOfWork; public MainActivity(IUnitOfWork unitOfWork, SomeActivity activity) { _unitOfWork = unitOfWork; } public void test() { _unitOfWork.Commit(); } } 

将这些行添加到BootStrapper.Configure()

 //register the test classes container.Register<SomeActivity>(); container.Register<MainActivity>(); 

根据代码行设置一个断点:

 _repositories.ToList().ForEach(x => x.Value.Submit()); 

最后,运行这个控制台testing代码:

 class Program { static void Main(string[] args) { Container container = new Container(); BootStrapper.Configure(container); container.Verify(); using (container.BeginLifetimeScope()) { MainActivity entryPoint = container.GetInstance<MainActivity>(); entryPoint.test(); } } } 

您会发现代码在中断点停止,并且已经准备好一个IRepository活动实例,并等待Submit()对数据库的任何更改。

你可以装饰你的UnitOfWork来处理事务等等。我将在这个时候推迟到强大的.NetJunkie,并推荐你在这里和这里阅读这两篇文章。

而不是注入库实例注入单个工厂对象将负责创build这些实例。 你的获得者将会使用那个工厂。