Generic Repository for Entity Framework

I have started trying to learn how to leverage the Entity Framework for a the re-write of the GiveCamp Starter Site and wanted to implement a generic repository for data access like I use on most of my projects.  I started with the example given by Mikael Henriksson’s Post Generic Repository for Entity Framework for Pluralized Entity Set.  I modified it to fit my standard Repository interface and took the liberty of simplifying it in a few places.

I have run this through several test and haven’t found any issues. I would love those with a critical eye to give this a look over and let me know if I am missing anything.

The IRepository Interface

public interface IRepository : IDisposable
  {
    T Get<T>(int id) where T : IEntityWithKey;
    T Get<T>(Expression<Func<T, bool>> predicate) where T : IEntityWithKey;
    IQueryable<T> Find<T>(Expression<Func<T, bool>> predicate) where T : IEntityWithKey; 
    T Save<T>(T entity) where T : IEntityWithKey;
    T Delete<T>(T entity) where T : IEntityWithKey;
  }

I did use the ObjectContextExtensions from Mikael’s post because they did such a good job of solving the issue of getting the EntitySetName. I am not going go into a lot of detail explaining what is going on because a feel the class pretty much explains itself.

The Repository Class:

public class EntityFrameworkRepository : IRepository   
{
  private readonly ObjectContext context;
  public EntityFrameworkRepository()
  {
    context = new WmdDemoEntities();
  }
  public EntityFrameworkRepository(ObjectContext entityContext)
  {
    context = entityContext;
  }
  public T Get<T>(int id) where T : IEntityWithKey
  {
    IEnumerable<KeyValuePair<string, object>> entityKeyValues = new[] { new KeyValuePair<string, object>("Id", id) };
    var key = new EntityKey(context.GetEntitySet<T>().Name, entityKeyValues);
    
    return (T)context.GetObjectByKey(key);
  }
  public T Get<T>(Expression<Func<T, bool>> predicate) where T : IEntityWithKey
  {
    return context.CreateQuery<T>("[" + context.GetEntitySet<T>().Name + "]")
      .Where(predicate)
      .FirstOrDefault();
  }
  public IQueryable<T> Find<T>(Expression<Func<T, bool>> predicate) where T : IEntityWithKey
  {
    return context
      .CreateQuery<T>("[" + context.GetEntitySet<T>().Name + "]")
      .Where(predicate);
  }
  
  public T Save<T>(T entity) where T : IEntityWithKey
  {
    object originalItem;
    
    if (context.TryGetObjectByKey(entity.EntityKey, out originalItem))
      context.ApplyPropertyChanges(entity.EntityKey.EntitySetName, entity); 
    else
      context.AddObject(entity.EntityKey.EntitySetName, entity);
      
    context.SaveChanges();
    
    return entity;
  }
  public T Delete<T>(T entity) where T : IEntityWithKey
  {
    context.DeleteObject(entity);
    context.SaveChanges();
    
    return entity;
  }
  
  public void Dispose()
  {
    context.Dispose();
  }
}
   

Here is an example of usage in a console application

class Program
{
  static void Main(string[] args)
  {
    IRepository repository = new EntityFrameworkRepository();
    
    var page = repository.Get<Page>(x => x.PageId == 1);
    Console.WriteLine("Title: {0}", page.Title);
    Console.WriteLine("Content: {0}", page.Content);
  
    repository.Dispose();
  
    Console.ReadLine();
  }
}

I love taking this approach to persistence because it is so flexible and allows me to swap out repository implementations with little issue.

Again love to hear some feedback on this approach.

Comments (4) -

Matt Lowrance
8/19/2010 5:04:54 PM #

Interesting post, I have a similar implementation at work, we use Linq 2 SQL but the concepts here are pretty close to the same.  I chose to implement my IRepository directly on the L2S Datacontext (in a partial class).

The nice thing is that the code that is used to get the EntitySet name, etc. can pretty much go away because since you're implementing the interface on the ObjectContext you have direct access to the data you need.  For example your Find method just becomes:

return CreateObjectSet<T>().Where(predicate); (Note you'd have to add a class constraint for this to compile)

In L2S it would be return this.GetTable<T>.Where(predicate);  

Its just an implementation detail but I started the same way and ended up feeling the the partial class implementation was a little bit cleaner, no table name string building etc.  Just a thought...

Also you could a second generic parameter like this T Get<T,TIDType>(TIDType id); to your Get method. That way you can call it for a table that doesn't have an int as its id field.  Not useful if you always use ints, but in our project that's often not the case.

Rob
8/19/2010 6:42:40 PM #

Nice! I love how short the whole thing is. These are the only things I would want different. And only the first one is important :)

1. I would want the repository to be transactional. So an explicit call to save changes would be added and I'd yank the call from Save and Delete.
2. I'd add a Find method that takes no arguments so there was a way to get all of something without having to pass an always true expression.
3. I'd just delegate to the Find method in the Get that takes and expression. It's the same bit of code. Very cool

jay.smith
8/19/2010 6:53:53 PM #

Matt,

Thanks for the info on CreateObjectSet<T> that will make it much shorter.  I don't have tables that don't have an int as it's id field in the current application.  It is always nice to own from UI to database on a project, but I am sure that will come in to play for some of my work projects that don't have an int as the id.

Jay

jay.smith
8/19/2010 7:00:46 PM #

Rob,

The transactional approach sounds like a good next step for me to tackle.  I agree on the Find method for getting all instances of an object from the database.  I had one of those "I am not sure why I have that there so I'll delete it moments", but now see the need. Fail, one step closer to success.

Jay

Comments are closed