15 Dec
2009

Entity Framework POCO (EF4): Generic Repository and Unit of Work Prototype

Category:UncategorizedTag: :

In my previous post I demonstrated how to create a simple mapping using the latest EF4 CTP. In this post I will look at how I can customize some infrastructure code in an attempt to align EF POCO ?Code Only? with existing patterns, while potentially increasing reuse and testability.

A popular pattern for ORM data access is the Repository pattern. Implementing a generic repository in EF4 gets much easier with ObjectSet<T>. One might argue that it is, in a sense, a Repository.

What I would like to do is ?Adapt? this interface to my own generic Repository. This will let me customize the interface to my own specifications and remove the dependency in my domain services on ObjectSet<T>.

Here is a great article based on the last CTP that does a nice job of laying out a Repository<T> strategy with a UnitOfWork, and here is another using nHibernate (see also UnitOfWork examples). If you are not familiar with the Generic Repository pattern and UnitOfWork, you should take a quick second and skim these before you continue. I want to take this implementation and try and change just a few things about it.

  • Static Unit of Work reference: First, I want to remove the Repository static reference to the UnitOfWork, which is how the Repository in the examples are resolving the ObjectContext/Session. Aside from not being a fan of static classes, I think it is the application Container?s responsibility to manage dependency resolution. Plus, I don’t really know that I want my Repository to have any reference to the UnitOfWork. I want the UnitOfWork to span across multiple repositories within a given transaction.
  • Object Lifetime: I would like to have more granular control over the UnitOfWork and ObjectContext lifetime. In the authors example, the UnitOfWork is managing the lifetime strategy, which is something the Container is perfect at handling. I will leave the UOW to transaction management only.
  • Constructor Injection: I think since the Repository has a hard dependency on the ObjectContext, that it would make the most sense to have the ObjectContext injected into Repository ctor.
  • Concrete ObjectContext reference: Since I will now be passing the ObjectContext into the ctor, I feel better if this was an interface. Not that I foresee a tremendous amount of testable value here, but I still don’t like taking a ctor dependency on a framework object if I can avoid it. Plus, this is prototype code, so why not?

Repository Interface

You will notice the interface remains unchanged from the first referenced article (Update: changed Func<T, bool> to Expression<Func<T, bool>> so that expressions can be evaluated correctly by ObjectQuery)

public interface IRepository<T> where T : class
{
    IQueryable<T> AsQueryable();
 
    IEnumerable<T> GetAll();
    IEnumerable<T> Find(Expression<Func<T, bool>> where);
    T Single(Expression<Func<T, bool>> where);
    T First(Expression<Func<T, bool>> where);
 
    void Delete(T entity);
    void Add(T entity);
    void Attach(T entity);

}

 

Generic Repository Implementation

As I described in the bullets above, my implementation does in fact take the IObjectContext as a ctor argument. Also, notice that I do not have any static references.

public class Repository<T> : IRepository<T> where T : class
{
   IObjectSet<T> _objectSet;
 
   public Repository(IObjectContext objectContext)
   {
       _objectSet = objectContext.CreateObjectSet<T>();
   }
 
   public IQueryable<T> AsQueryable()
   {
       return _objectSet;
   }
 
   public IEnumerable<T> GetAll()
   {
       return _objectSet.ToList();
   }
 
   public IEnumerable<T> Find(Expression<Func<T, bool>> where)
   {
       return _objectSet.Where(where);
   }
 
   public T Single(Expression<Func<T, bool>> where)
   {
       return _objectSet.Single(where);
   }
 
   public T First(Expression<Func<T, bool>> where)
   {
       return _objectSet.First(where);
   }
 
   public void Delete(T entity)
   {
       _objectSet.DeleteObject(entity);
   }
 
   public void Add(T entity)
   {
       _objectSet.AddObject(entity);
   }
 
   public void Attach(T entity)
   {
       _objectSet.Attach(entity);
   }

}

 

Unit of Work

Just like EF4 ObjectSet does a lot out of box for our Repository, the EF ObjectContext really does a lot of the work for us in regards to managing the UnitOfWork. The Object context is already capable of handling a transaction across many operations over different types. So, again, we are going to just add a little wrapper around the context and call it a UnitOfWork. This will give me a nice hook where my infrastructure can snag a reference to the ObjectContext and Commit the transaction changes, for example, at the end of a WCF, Web or DataService request.

interface IUnitOfWork
{
    void Commit();
}
 
public class UnitOfWork: IUnitOfWork, IDisposable
{
    private readonly IObjectContext _objectContext;
 
    public UnitOfWork(IObjectContext objectContext)
    {
        _objectContext = objectContext;
    }
 
    public void Dispose()
    {
        if (_objectContext != null)
        {
            _objectContext.Dispose();
        }
        GC.SuppressFinalize(this);
    }
 
    public void Commit()
    {
        _objectContext.SaveChanges();
    }
}

 

The Object Context Adapter

Just some Adapter 101 code here to abstract away the Concrete Context

public interface IObjectContext : IDisposable
{
    IObjectSet<T> CreateObjectSet<T>() where T : class;
    void SaveChanges();
}
 
public class ObjectContextAdapter : IObjectContext
{
    readonly ObjectContext _context;
 
    public ObjectContextAdapter(ObjectContext context)
    {
        _context = context;
    }
 
    public void Dispose()
    {
        _context.Dispose();
    }
 
    public IObjectSet<T> CreateObjectSet<T>() where T : class
    {
        return _context.CreateObjectSet<T>();
    }
 
    public void SaveChanges()
    {
        _context.SaveChanges();
    }
}

 

Using the Repository

Without out my application Container, here is how I would code up the new abstractions:

//...
// a bunch of ugly set up code here, see previous post
//...
 
var context = builder.Create(connection);
var contextAdapter = new ObjectContextAdapter(context);
var unitOfWork = new UnitOfWork(contextAdapter);
 
var teamRepository = new Repository<Team>(contextAdapter);
var newTeam = new Team { Name = "Da Bears" };
 
teamRepository.Add(newTeam);
unitOfWork.Commit();
 
var team = teamRepository.First(x => x.Name == "Da Bears");
Console.WriteLine(team.Name);
 
context.Dispose();

Admittedly, this is not very pretty and is still way more than I want to deal with on regular basis. In my next post I will demonstrate how I will tie all this together, EF Configuration, Repository and UnitOfWork using a Unity Extension.

Please keep in mind this is prototype, untested code on a CTP release. Code at your own risk!

Find me

RSS
Facebook
Twitter
LinkedIn
SOCIALICON
SOCIALICON

Disclaimer

The opinions and content expressed here are my own and not those of my employer.