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

December 15th, 2009

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!

  • Cibrax

    A common problem with methods that receive an Expression tree like Find, Single or First in your example is that they can not easily be mocked in an unit test with most of common Mocking frameworks out there. I can tell this from experience with previous developments.

  • zambak zambak

    Hi

    Since Entity Framework 4.1 there is allready IObjectContextAdapter…Could we have used

        public class UnitOfWork : IUnitOfWork, IDisposable
        {
            private readonly ObjectContext _objectContext;

            public UnitOfWork(IObjectContextAdapter objectContextAdapter)
            {
                _objectContext = objectContextAdapter.ObjectContext;
            } //ommited for brevity }

    and

        public class Repository : IRepository where T : class
        {
            IObjectSet _objectSet;

            public Repository(IObjectContextAdapter objectContextAdapter)
            {
                _objectSet = objectContextAdapter.ObjectContext.CreateObjectSet();
            }

    //ommited for brevity }then usage becomes             var db = new MyEfCodeFirstContext();  // create context (could be auto wired I guess)

                var uow = new UnitOfWork(db);    // unit of workvar teamRepository = new Repository(db); // no adapter needed (EF provides one)
    var newTeam = new Team { Name = “Da Bears” };Thoughts?ThanksZ….

    • Big D

      Hi

      You mentioned that you are not keeping a static reference to unit of work…what if the user is work across multiple screens and getting and updating data within those screens?

    • http://www.facebook.com/warren.lafrance Warren LaFrance

      Did you ever get an answer to your question?

  • Gavin Luo

    ??????

  • Efekaptan

    Hi, you can also add an (frequently used) order by function

    public IEnumerable GetAllOrderBy(Func keySelector) {
                return _objectSet.OrderBy(keySelector).ToList();
     }

  • http://www.facebook.com/profile.php?id=751256053 Mustafa Düman

    Hello, 

    1- 

    - i’m looking for “generic repository” and “generic unit of work” interface declerations and concrete implementation of these with EF.

    Since i want generic interface, the interfaces must not include anything specific to EF.

    Is IObjectSet specific to EF? If so, i think this interface is not generic enough. 

    2- I think the unit of work interface having just a “commit” function is not generic at all. It’s true just for your implementation logic…

    Just a Commit?  Let’s forget about repository(since it’s not mentioned in the interface). Is any concrete class implementing a simple commit function be UOW?  What will it commit???? Not generic or meaningful at all..

    The best UOW interface i’ve met so for is below. 

    If you can implement these with EF then it would be generic..

    Interfaces
    ————————————————————————
    public interface IAggregateRoot   
    {}

    public interface IUnitOfWorkRepository   
    {       
    void PersistCreationOf(IAggregateRoot entity);       
    void PersistUpdateOf(IAggregateRoot entity);       
    void PersistDeletionOf(IAggregateRoot entity);   
    }

    public interface IUnitOfWork
    {
    void RegisterAmended(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
    void RegisterNew(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
    void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
    void Commit();
    }

    ————————————————————————Concrete UOW implementation ————————————————————————

    public class UnitOfWork : IUnitOfWork    
    {
    private Dictionary addedEntities;
    private Dictionary changedEntities;
    private Dictionary deletedEntities;

    public UnitOfWork()        {            addedEntities = new Dictionary();            changedEntities = new Dictionary();            deletedEntities = new Dictionary();        }        public void RegisterAmended(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)        {            if (!changedEntities.ContainsKey(entity))            {                changedEntities.Add(entity, unitofWorkRepository);            }        }        public void RegisterNew(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)        {            if (!addedEntities.ContainsKey(entity))            {                addedEntities.Add(entity, unitofWorkRepository);            };        }        public void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)        {            if (!deletedEntities.ContainsKey(entity))            {                deletedEntities.Add(entity, unitofWorkRepository);            }        }                public void Commit()        {            using (TransactionScope scope = new TransactionScope())            {                foreach (IAggregateRoot entity in this.addedEntities.Keys)                {                    this.addedEntities[entity].PersistCreationOf(entity);                }                foreach (IAggregateRoot entity in this.changedEntities.Keys)                {                    this.changedEntities[entity].PersistUpdateOf(entity);                }                foreach (IAggregateRoot entity in this.deletedEntities.Keys)                {                    this.deletedEntities[entity].PersistDeletionOf(entity);                }                scope.Complete();             }        }    }

    ————————————————————————

    These interfaces are from a book. Samples are freely available. The interfaces are in chapter 7 samples: 

    http://www.wrox.com/WileyCDA/WroxTitle/Professional-ASP-NET-Design-Patterns.productCd-0470292784,descCd-DOWNLOAD.html)