且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

依赖注入工作格局的单位使用信息库

更新时间:2023-02-05 22:45:34

解决这个是不是让的UnitOfWork 负责创建每个通过容器注入,而是要让它每个责任来确保的UnitOfWork 知道在实例它的存在。

A way to approach this is to not make the UnitOfWork responsible for creating each Repository through Container injection, but instead to make it the responsibility of each Repository to ensure that the UnitOfWork knows of its existence upon instantiation.

这将确保


  • 的UnitOfWork 并不需要更改每个新的

  • 您没有使用服务定位器(被许多人认为是反模式

  • your UnitOfWork doesn't need to change for each new Repository
  • you are not using a service locator (considered by many to be an anti-pattern)

这是***的一些code证明 - 我使用 SimpleInjector 这样的例子是基于解​​决此问题:

This is best demonstrated with some code - I use SimpleInjector so the examples are based around this:

抽象开始:

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

每个必须的使用的UnitOfWork 注册本身,这可以这样做改变抽象父类 GenericRepository ,以确保它完成的:

Each Repository must register itself with the UnitOfWork and this can be done by changing the abstract parent class GenericRepository to ensure it is done:

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

每个真正的继承的 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 的所有定义的实例,并提供终身范围内进行注册,以确保它们全部存活的寿命你交易:

The container registration can be set up to automatically pick up all the defined instances of IRepository and register them with a lifetime scope to ensure they all survive for the lifetime of your transaction:

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 的那被实例化的服务调用内,你必须编译所有的仓库都被定义时验证。您code是对扩展开放,但对修改封闭

With these abstractions and an architecture built around DI you have a UnitOfWork that knows of all Repository's that have been instantiated within any service call and you have compile time validation that all of your repositories have been defined. Your code is open for extension but closed for modification.

要测试这一切 - 添加这些类

To test all this - add these classes

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

将一个破发点对code线:

Put a break-point against the line of code:

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

最后,运行此控制台测试code:

And finally, run this Console test code:

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

您会发现code停在破发点,你有一个 IRepository 准备和等待,以提交一个活动实例()对数据库的任何更改。

You'll find the code stops at the break point and you have one active instance of a IRepository ready and waiting to Submit() any changes to the database.

您可以装饰你的UnitOfWork处理事务等。我会推迟到浩浩荡荡.NetJunkie在这一点上我建议你阅读这两篇文章的这里这里一>

You can decorate your UnitOfWork to handle transactions etc. I will defer to the mighty .NetJunkie at this point and recommend you read these two articles here and here.