Reputation: 77
I'm trying to implement the unit of work pattern (UoW) for my repositories in C#/.NET. My plan is to give UoW as a parameter to repositories. Here's an example how it could be used:
using (var uow = new UnitOfWork())
{
var itemRepository = new ItemRepository(uow);
itemRepository.Add(new Item());
uow.Commit();
}
Also, for simple operations (when transactions are not needed), repositories should be able to be used without Unit of Work:
var itemRepository = new ItemRepository();
var item = itemRepository.Get(itemId);
UnitOfWork/Repository could get a database connection from ConnectionFactory. The connection factory receives connection options via dependency injection. However, here's my problem: How do repositories get reference to ConnectionFactory instance?
Repositories are created manually, so they can't have dependencies injected via a constructor. One option would be to have repository factories, which could have their dependencies injected. In that case, usage could be like this:
using (var uow = new UnitOfWork())
{
var itemRepository = itemRepositoryFactory.Create(uow);
itemRepository.Add(new Item());
uow.Commit();
}
The drawback in that solution is that each repository will need its own factory, and there will be quite many. Is there another solution to circumvent this problem?
Upvotes: 0
Views: 2821
Reputation: 535
I would definitely register the UOW as a scoped dependency.
Scoped dependencies live for the lifetime of the container that creates them. Typically, frameworks would generate a child container from the parent container in order to execute some piece of work. For example, ASP.NET Core spawns a child container for a request and then disposes it when the request is finished. This would mean that the UOW instance that is getting injected is the same instance throughout the object graph for that request only.
You can also create your own scopes, if needed. I have done this twice for example:
This is how you would achieve this using Microsoft's DI framework:
var collection = new ServiceCollection();
collection.AddScoped<IUnitOfWork, UnitOfWork>();
var provider = collection.BuildServiceProvider();
var puow = provider.GetRequiredService<IUnitOfWork>();
for(int i = 0; i < 2; i++)
{
//Create the new scope
using var childContainer = provider.CreateScope();
//IUnitOfWork will be a singleton instance in this scope.
var c1uow = childContainer.ServiceProvider.GetRequiredService<IUnitOfWork>();
var c2uow = childContainer.ServiceProvider.GetRequiredService<IUnitOfWork>();
// This should true, since they come from the same scope.
var sameScope = c1uow == c2uow;
//With the requested IUnitOfWork from provider instead, it would be a different instance
//Therefore, this should be false
var diffScope = puow == c1uow;
}
This would allow you to simply inject IUnitOfWork into each repo, without having to create a factory for each repo.
This would work out of the box if you are writing an application in ASP.NET Core. Simply register the dependency as scope, as so
collection.AddScoped<IUnitOfWork, UnitOfWork>();
and then have it injected into the repos that you need. You don't have to worry about creating a new scope since the framework does that for you for each http request that the application receives.
I would really recommend reading Mark Seemann's book "Dependency Injection Principles, Practices, and Patterns". It really goes in depth about what dependency injection is and how it works. Not only that, I find him to be a great writer.
Upvotes: 1