我想创建一个工作单元类,以类似于此方法的方式包装存储库。
我遇到的问题是尝试通过使用IRepository接口替换示例中的通用存储库来实现依赖项注入。在链接文章的uow中,他们使用getters检查存储库是否已实例化,如果尚未实例化,则将其实例化。
public GenericRepository<Department> DepartmentRepository { get { if (this.departmentRepository == null) { this.departmentRepository = new GenericRepository<Department>(context); } return departmentRepository; } }
这是紧密耦合的。
我可以看到两种解决方法。
1的问题是,如果我注入了所有存储库,则即使我不在该特定工作单元实例中使用它们,也必须实例化每个存储库。因此,这样做会产生开销。我在想使用一个数据库范围的工作单元类,因此这将导致大量不必要的实例化和一个巨大的构造函数。
2的问题在于,很容易忘记设置并以空引用异常结束。
在这种情况下,是否有任何最佳做法?还有我错过的其他选择吗?
我只是进入依赖注入,并完成了我可以在该主题上找到的所有研究,但是我可能缺少一些关键的东西。
解决此问题的方法不是通过容器注入使UnitOfWork创建每个对象负责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以确保完成来完成:
GenericRepository
public abstract class GenericRepository<T> : IRepository<T> where T : class { public GenericRepository(IUnitOfWork unitOfWork) { unitOfWork.Register(this); } }
每个实数都Repository继承自GenericRepository:
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) { } }
添加的物理实现,UnitOfWork您就可以设置好:
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并在生命周期范围内注册它们,以确保它们在事务的生命周期中都有效:
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构建的体系结构,您就UnitOfWork可以知道Repository在任何服务调用中都已实例化的所有对象,并且可以通过编译时验证来确定所有存储库都已定义。您的代码可以扩展,但是可以修改。
要测试所有这些-添加这些类
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()
BootStrapper.Configure()
//register the test classes container.Register<SomeActivity>(); container.Register<MainActivity>();
在代码行中放置一个断点:
_repositories.ToList().ForEach(x => x.Value.Submit());
最后,运行以下控制台测试代码:
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(); } } }
您会发现代码在断点处停止,并且您有一个处于活动状态的IRepositoryready 实例,正在等待Submit()数据库的任何更改。
Submit()
您可以装饰UnitOfWork来处理事务等。此时,我将遵循强大的.NetJunkie,并建议您在此处和此处阅读这两篇文章。