How can I inject the Repositories to the UnitOfWor

2019-07-06 22:26发布

I've implemented my UnitOfWork so that it keeps references to all repositories.

public interface IUnitOfWork
{
   void Commit();
   void RollBack();
}

public interface IMyUnitOfWork : IUnitOfWork
{
   IFooRepository Foos { get; }
   IBarRepository Bars { get; }
   // Other repositories ...
}

Note that the repositories implements a generic type of repository interface.

public interface IFooRepository : IRepository<Entities.Foo>
{
    // FooRepository specific methods goes here.
}

public interface IRepository<T> : IRepository
    where T : class
{
}

Now how can I inject these repository to my UnitOfWork. Of course I want them with a lazy loading behavior. For example:

public class ConcreteUnitOfWork : IMyUnitOfWork
{
   private readonly IUnityContainer unityContainer;
   private IFooRepository fooRepository;

   public ConcreteUnitOfWork(IUnityContainer unityContainer)
   {
      this.repositoryFactory = repositoryFactory;
   }

   public IFooRepository Foos
   {
      get 
      { 
         return this.fooRepository ?? 
            (this.fooRepository = unityContainer.Resolve<IFooRepository>()); 
      }
   }
}

I know passing the Unity container to the UnitOfWork is incorrect but what pattern would you offer to solve this issue?

You may mention that I shouldn't keep the repository references in the UnitOfWork but please suppose a service class which needs several repositories. With this design I can just pass the UnitOfWork as the constructor parameter (Constructor Injection) to the service class, but if I didn't keep the repository references in UnitOfWork, I would have to pass all needed repositories as constructor parameters and you know what it leads to.

-- UPDATE --

Please let me know if I'm absolutely wrong and I should never compose the repositories in UnitOfWork. Then please give me a solution about "Constructor Over-injection" here.

-- UPDATE2 --

It seems that composing (referencing to) the repositories from UnitOfWork breaks the Open/Closed principle as we need to change the UnitOfWork class when we add a new repository (add a new property).

If it's right then I should consider a refactoring. Would you please give me some ideas?

1条回答
Anthone
2楼-- · 2019-07-06 23:07

It seems as though the current design proposal mixes more than one responsibility into the IMyUnitOfWork interface. You say that this is because otherwise a service class might need to take each Repository independently. I'm assuming you mean something like this:

public MyService(
   IUnitOfWork uow,
   IFooRepository fooRepository,
   IBarRepository barRepository)

This seems to me to be a much simpler and cleaner design.

But then what about Constructor Over-injection?

Well, there's that... but the thing is that this is exactly the same problem you now have with your ConcreteUnitOfWork implementation. You haven't solved the Constructor Over-injection smell at all - you've just moved it to another class.

Actually, by moving it to ConcreteUnitOfWork you've made it more difficult to deal with the situation. Because ConcreteUnitOfWork is a pure infrastructure class (or a support class, if you will) it doesn't have any business context, so it's really hard to suggest a way resolve the Constructor Over-injection smell here.

On the other hand, a given Service (or perhaps a Controller) would tend to be more specialized and have knowledge of the business context, so it wouldn't need every repository in order to do its job - or if it does, it probably attempts to do too much.

Such a specific business component can better be refactored to a Facade Service.

查看更多
登录 后发表回答