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.
Don't dispose DbContext objects. Although the DbContext implements IDisposable , you shouldn't manually dispose it, nor should you wrap it in a using statement. DbContext manages its own lifetime; when your data access request is completed, DbContext will automatically close the database connection for you.
Dispose() Calls the protected Dispose method. Dispose(Boolean) Disposes the context. The underlying ObjectContext is also disposed if it was created is by this context or ownership was passed to this context when this context was created.
The Repository pattern allows you to easily test your application with unit tests. Remember that unit tests only test your code, not infrastructure, so the repository abstractions make it easier to achieve that goal.
No, the repository/unit-of-work pattern (shortened to Rep/UoW) isn't useful with EF Core. EF Core already implements a Rep/UoW pattern, so layering another Rep/UoW pattern on top of EF Core isn't helpful.
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(); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With