Repository Pattern in Entity framework 4 when should we dispose?

user9969 picture user9969 · Nov 28, 2010 · Viewed 14.2k times · Source

New to EF and I have noticed that using a repository pattern can really simplify things and will allow me to do some mocking too.So far so good.

My Question

A typical usage of the objectContext is to destroy as soon as possible see below

using (var context = new SchoolEntities())
{    
    context.AddToDepartments(department);    
    context.SaveChanges();
}

Using the Repository pattern I have noticed that nobody actually uses the "Using Pattern" eg

using (var repository= new Repository<Student>(new MyContext))
{    
    repository.Add(myStudentEntity)  
    repository.SaveChanges();
}

Should the idea be that we should dispose of the context as soon as possible otherwise the memory might leak or get very big?

Can anyone clarify? Thanks a lot.

Answer

Ladislav Mrnka picture Ladislav Mrnka · Nov 28, 2010

Yes you should dispose context even if you are using repository. It is not clear what advantage does your Repository implementation give you because you are still providing ObjectContext as constructor's parameter, aren't you?

IMO the main reason for using Repository and custom UnitOfWork is persistance ignorance = hidding EF code from upper application layers because ObjectContext + ObjectSet themselves are implementation of repository and unit of work patterns.

If I'm using repository, I'm always wrapping whole EF code, so the public interface of my repository doesn't provide any information about EF related infrastructure. In that case it is up to me how I deal with ObjectContext.

For easy straight forward CRUD scenarios, I can wrap context creation and disposing into each repository method. In more complex scenarios I'm using additional class - UnitOfWork (UoW), which wraps context creation and disposing and it triggers saving changes into database. It also acts as factory for all repositories and passes instance of created context into repositories' constructors.

Most of the time I'm programming services or web applications so I'm dealing with detached objects. I'm always using single UoW instance for request processing. So the UoW is created at the beginning of request processing and released at the end of request processing. In case of WinForms / WPF applications and attached objects I think the good idea is to have UoW / ObjectContext instance "per form" - there is article describing this approach with NHibernate session (same as EF ObjectContext) in MSDN magazine.

Some starting implementation of UnitOfWork and Repository patterns:

Context holder and abstract factory for repositories

public interface IUnitOfWork
{
  IRepository<MyEntity> MyEntityRepository { get; }
  // Repositories for other entities

  SaveChanges();
}

Repository for detached entities

public interface IRepository<T> where T : class
{
  IQueryable<T> GetQuery();
  void Insert(T entity);
  void Delete(T entity);

  // In very complex scenarios with big object graphs you will probably give up
  // using detached approach and you will always load your entities from DB before
  // deleting or updating them. In such case you will not need Update method at all.

  void Update(T entity);
}

Disposable implementation of UnitOfWork wrapping Enitity framework

public class UnitOfWork : IUnitOfWork, IDisposable
{
   private ObjectContext _context = null;

   public UnitOfWork(string connectionString)
   {
     if (String.IsNullOrEmpty(connectionString)) throw new ArgumentNullException("connectionString");
     _context = new ObjectContext(connectionString);
   }

   private IRepository<MyEntity> _myEntityRepository;

   public IRepository<MyEntity> MyEntityRepository
   {
     get
     {
        return _myEntityRepository ?? (_myEntityRepository = new GeneralRepository<MyEntity>(_context));
     }
   }

   public void SaveChanges()
   {
     _context.SaveChanges();
   }

   public void Dispose()
   {
     Dispose(true);
     GC.SuppressFinalize(this);
   }

   protected virtual void Dispose(bool disposing)
   {
     if (disposing)
     {
       if (_context != null)
       {
         _context.Dispose();
         _context = null;
       }
     }
   }
}

Base repository implementation

public class GeneralRepository<T> : IRepository<T> where T : class
{
  private ObjectSet<T> _set;
  private ObjectContext _context;


  public GeneralRepository(ObjectContext context)
  {
    if (context == null) throw new ArgumentNullException("context");
    _context = context;
    _set = context.CreateObjectSet<T>();
  }

  // Override this method for example if you need Includes
  public virtual IQueryable<T> GetQuery()
  {
    return _set;
  }

  // Override following methods if you are working with object graphs.
  // Methods do not execute operations in database. It is responsibility of 
  // UnitOfWork to trigger the execution

  public virtual void Insert(T entity)
  {
    if (entity == null) throw new ArgumentNullException("entity");
    _set.AddObject(entity);
  }

  // These impelementations are for detached scenarios like web application

  public virtual void Delete(T entity)
  {
    if (entity == null) throw new ArgumentNullException("entity");
    _set.Attach(entity);
    _set.DeleteObject(entity);
  }

  public virtual void Update(T entity)
  {
    if (entity == null) throw new ArgumentNullException("entity");
    _set.Attach(entity);
    _context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
  }
}

Usage when selecting data

using (var uow = new UnitOfWork(connectionString))
{
  var entity = uow.MyEntitiesRepository.GetQuery().Single(e => e.Id == 1);
  // Do something with entity
}

Usage when modifing data

using (var uow = new UnitOfWork(connectionString))
{
  uow.MyEntitiesRepository.Update(entity);
  uow.SaveChanges();
}