I am implementing Unit of Work. This is part of my interface:
public interface IUnitOfWork
{
void Add(object entity);
void Update(object entity);
void Delete(object entity);
void Commit();
}
It looks like from examples I’ve found online or in books, the Unit of Work is forced to work with type “object”, as we can be adding any “type” of entity to the uow.
Not a big deal until it comes time to Commit(). When I commit, given an entity type, I need to look-up the repository based on the entity type, and then call the appropriate action.
For example, I have an entity type named Expert
public class Expert
{
public object ID { get; set; }
public string Name { get; set; }
}
Expert has a repository named ExpertRepository. All Repositories in my application implement IRepository:
public interface IRepository<T>
{
void Create(T item);
void Update(T item);
void Delete(T item);
}
public class ExpertRepository : IRepository<Expert>
{
public void Create(Expert item)
{
//TSQL to insert
}
public void Update(Expert item)
{
//TSQL to update
}
public void Delete(Expert item)
{
//TSQL to delete
}
}
I want to clarify that it is not the responsibility of my Repositories to add, update, or delete an entity from my uow, rather, I’ll have the consuming code (maybe in a Service Layer) new up the uow, and then add directly to it… when my app is ready, it will call Commit().
This does two things. It allows my consuming code to decide how it wants the entity to be persisted. Either the consuming code can call .Create() directly on the Repository to persist the entity with no uow, or the consuming code can start a uow, call .Add() on the uow, and then when .Commit() is called, the uow will go through all entities, and by action type (add, update delete), new up the appropriate repository, and the TSQL code will execute.
Now, the problem I’m running into is when I’m looping through the Add, Update, and Delete collections in my uow. Here is a code snippet:
public void Commit()
{
using (TransactionScope tx = new TransactionScope())
{
try
{
foreach (object item in addedItems)
{
if (item.GetType() == typeof(Expert))
{
IRepository<Expert> repository = new ExpertRepository();
repository.Create((Expert)item);
}
}
}
}
}
I have to resolve entity type of what’s in the object collection via the item variable. Then I need to new up that entity’s Repository (also providing the correct type to the IRepository interface), and then call .Create().
That’s all well and good, but I don’t want to have these conditional checks for every possible entity, for the entity’s interface, and the entity’s repository sitting in my uow. That’s very very bad.
I know that an IoC container could help here (such as Unity), but is there any IoC container that can resolve generic types at runtime? I ask, b/c IRepository will need to be typed correctly to be a var that holds the instance of a given entity’s repository.
I’ve made some design decisions here such as putting the strong typing with the Repositories, not the UOW. For instance, I don’t want a .Create() method sitting on a Repository that takes type object, esp. since my Repositories have a one-to-one relationship with my entities (Expert, ExpertRepository).
I’ve also decided that since most of the repository calls are the same, I don’t want an interface for each repository (aka, ExpertRepository implements IExpertRepository). That doesn’t make sense, I think using generics here is the answer.
But it all comes down to the problem in my uow. How do I get what I need to implement it correctly.
Any suggestions or pointers in the right direction would be appreciated.
Thanks!
IoC is the way to go. Some of them supports open generics. Let’s take StructureMap as an example. You’ll need to have registration code similiar to this:
And then, your
Commitmethod can just ask the container for the implementation for given type:(You’ll need to have non-generic
IRepositoryinterface that will cover the needs of yourCommitmethod, but I believe that’s no problem when implementations can vary).