In a project I'm working on, the data access layer has evolved to something that somewhat resembles the Unit Of Work and Repository patterns, at least they started with those names, I'm not entirely sure with how far they've drifted, if they can still be called that.
For classes data access, an implementation IWorkUnitFactory
is passed as a constructor parameter from the IoC container. This is a rather simple interface:
public interface IWorkUnitFactory
{
IWorkUnit Begin();
}
The IWorkUnit
interface it returns looks like this:
public interface IWorkUnit : IDisposable
{
T Insert<T>(T entity) where T : class;
T Load<T>(int id) where T : class;
void Delete<T>(int id) where T : class;
void Delete<T>(T entity) where T : class;
T Update<T>(T entity) where T : class;
T InsertOrUpdate<T>(T entity) where T : class;
IQueryable<T> Query<T>() where T : class;
IEnumerable<T> Execute<T>(string queryName, IDictionary<string, object> parameters);
void Commit();
void Rollback();
}
My IWorkUnitFactory
implementation for NHibernate basically just creates an NHibernate session, and passes it to the NHibernate implementation of IWorkUnit
, which is just a rather thin wrapper around the NHibernate session, which starts a transaction in its constructor, and rolls it back in the Dispose
implementation unless the Commit
method is called.
Then, anywhere data access happens, it follows this pattern:
using(var workUnit = WorkUnitFactory.Begin())
{
//Boring data access code here
workUnit.Commit();
}
Next up are the Repository
classes. These don't have any common inheritance or interface implementations, they just follow a few conventions, the main one being taking an IWorkUnit
in its constructor. These classes contain the interaction with the IWorkUnit
for operations like GetById
, Find
, Insert
, Update
, etc, and are responsible for small bits of logic (the Update
method updates the LastUpdated
field on the entity, Find
determines what fields to search based on its parameters, etc).
So, for example, a Repository for the User entity might look something like this:
public class UserRepository
{
private readonly IWorkUnit workUnit;
public UserRepository(IWorkUnit workUnit)
{
this.workUnit = workUnit;
}
public virtual User GetByEmail(string email)
{
return workUnit.Query<User>().FirstOrDefault(u => u.Email == email);
}
public virtual User Update(User user, User updater)
{
user.ModifiedBy = updater;
user.Modified = DateTimeOffset.Now;
return workUnit.Update(user);
}
}
Then, code to update a user would look something like this:
using(var workUnit = WorkUnitFactory.Begin())
{
var userRepo = new UserRepository(workUnit);
var userToEdit = userRepo.GetByEmail("[email protected]");
//Do some stuff to userToEdit here
userRepo.Update(userToEdit, currentRequestUser); //currentRequestUser is just whoever is performing the action
workUnit.Commit();
}
Any feedback on better naming for these things, or better methods? This has served me rather well, with the only thing I don't really like is creating the repository instances like that, But I can't think of a way to handle transactions and keep the somewhat lower level data access code away from higher level business logic.