解决这个问题的一种方法是不使UnitOfWork
负责创建每个Repository
通过容器注入,而是让它成为每个人的责任Repository
以确保UnitOfWork
在实例化时知道它的存在。
这将确保
- your
UnitOfWork
不需要为每个新的改变Repository
- 您没有使用服务定位器(许多人认为是反模式)
这可以通过一些代码得到最好的证明 - 我使用简单注入器所以这些例子都是基于这个:
从Repository
抽象:
public interface IRepository
{
void Submit();
}
public interface IRepository<T> :IRepository where T : class { }
public abstract class GenericRepository<T> : IRepository<T> where T : class { }
and the UnitOfWork
public interface IUnitOfWork
{
void Register(IRepository repository);
void Commit();
}
Each Repository
must将自己注册到UnitOfWork
这可以通过更改抽象父类来完成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
并在生命周期范围内注册它们,以确保它们在您的交易生命周期内都存活:
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()
//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();
}
}
}
您会发现代码在断点处停止,并且您有一个活动的实例IRepository
准备好并等待Submit()
对数据库的任何更改。
您可以装饰您的 UnitOfWork 来处理事务等。此时我将遵循强大的 .NetJunkie 并建议您阅读这两篇文章here and here.