30

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.

user247702
  • 23,641
  • 15
  • 110
  • 157
user9969
  • 15,632
  • 39
  • 107
  • 175

1 Answers1

49

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();
}
user247702
  • 23,641
  • 15
  • 110
  • 157
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • 1
    Fantastic.Thanks!!! the only issue i have with these repositories is that none of them handle the "Include" Eager loading. How do you do eager loading with your repository? – user9969 Nov 28 '10 at 18:49
  • 1
    That is the tricky part, because Include is feature of EF ObjectQuery. I'm usually creating inherited repository from GeneralRepository and add necessary Includes into overriden GetQuery. But if you need to activate eager loading only for some queries it will not help you. In that case you need something else. I can imagine implementing something like LoadOptions from Linq-To-Sql and passing this options into UnitOfWork or Repository. Then using optins to set all includes. – Ladislav Mrnka Nov 28 '10 at 20:56
  • 3
    Very in depth answer - however, your `UnitOfWork` class has a single, local-scoped `IRepository` instance, which means the Unit of Work is defining the repository to work with. This is not correct. The point of the Unit of Work is to handle transactions across multiple repositories (the UoW usually accepts 1-* repositories via its ctor). This implementation doesn't really handle that at all. Maybe this is fine for the OP though. – RPM1984 Nov 28 '10 at 22:59
  • @RPM1984: Yes, that is true. My implementation has one instance of repository for each entity type. I'm combining UoW with Abstract factory for my repositories. At the moment this implementation provides me functionality I need but your proposal also sounds good. – Ladislav Mrnka Nov 29 '10 at 00:07
  • @RPM1984.Do you have an example of what you mean.So if I have 10 repositories EG "CustomerRepository","EmployeeRepository" etc... and I stick them in the UnitOfWOrk ,would not that do what you mean? thanks for any feedback – user9969 Nov 29 '10 at 05:55
  • Great answer @Ladislav Mrnka, I'd also be interested in seeing an example of multiple repositories if you have a spare moment. – Alex KeySmith Mar 21 '12 at 09:31
  • @LadislavMrnka Could UnitOfWork be extended to also return a generic repository of type T? Something like public IRepository GenericRepository() { ... }. If so, how? Also, in your using statement `using (var uow = new UnitOfWork(connectionString))` is `var` an implementation of `UnitOfWork` or `IUnitOfWork`? Wouldn't `IUnitOfWork` be the better of the two? – GFoley83 May 25 '13 at 05:27
  • Hey, I am trying to use your example in my code, using TDD. When I use the , using UnitOfWork, how can i mock out the UnitOfWork in my unit test. to test the implementation of it inside my business logic layer? – Mitch May 20 '16 at 14:34
  • You mock `IUnitOfWork` interface to test your business layer, not to test implementation of unit of work. – Ladislav Mrnka May 23 '16 at 13:59