Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Of Work & Generic Repository with Entity Framework 5

I'm using ASP.NET MVC 4 with Entity Framework 5. I have model classes and Entity Maps to map existing tables to those model classes. All this is setup fine and works great.

Now I want to mock this. I created Unit Of Work that takes the DataContext and uses a Generic Repository. Upon that I built services to be able to get data from many repositories at once and only needing to have one instance of the DataContext. This also works great.

Now to the problem: I want to test the services, with mock data. When I create the Unit Of Work instance, I want to be able to insert a DataContext that is mocked instead of the real DataContext.

I tried to create a IContext interface and let the real and mocked DataContext implement that but ran into problems with DbSet. I tried to use IDbSet and creating a FakeDbSet but without success. I also read on the internet that mocking the context with IDbSet and using a FakeDbSet is a bad approach.

Do you have any idea what would be the best way to achieve this? What I have now is the behavior I would like to keep, but would really like to be able to mock the data from the Model classes in the DataContext.

I'm aware of that Entity Framework already comes with Unit Of Work behavior and that you don't need to add extra behavior on top of that. But I wanted to wrap that inside of another class that keeps track of all the repositories (called UnitOfWork class).

Edit: I wrote two articles explaining my solution with both LINQ and Entity Framework.

http://gaui.is/how-to-mock-the-datacontext-linq/

http://gaui.is/how-to-mock-the-datacontext-entity-framework/

Here's my code:

IRepository.cs

public interface IRepository<T> where T : class {     void Add(T entity);     void Delete(T entity);     void Update(T entity);     T GetById(long Id);     IEnumerable<T> All();     IEnumerable<T> Find(Expression<Func<T, bool>> predicate); } 

IUnitOfWork.cs

public interface IUnitOfWork : IDisposable {     IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;     void Save(); } 

Repository.cs

public class Repository<T> : IRepository<T> where T : class {     private readonly IDbContext _context;     private readonly IDbSet<T> _dbset;      public Repository(IDbContext context)     {         _context = context;         _dbset = context.Set<T>();     }      public virtual void Add(T entity)     {         _dbset.Add(entity);     }      public virtual void Delete(T entity)     {         var entry = _context.Entry(entity);         entry.State = System.Data.EntityState.Deleted;     }      public virtual void Update(T entity)     {         var entry = _context.Entry(entity);         _dbset.Attach(entity);         entry.State = System.Data.EntityState.Modified;     }      public virtual T GetById(long id)     {         return _dbset.Find(id);     }      public virtual IEnumerable<T> All()     {         return _dbset;     }      public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)     {         return _dbset.Where(predicate);     } } 

UnitOfWork.cs

public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new() {     private readonly IDbContext _ctx;     private Dictionary<Type, object> _repositories;     private bool _disposed;      public UnitOfWork()     {         _ctx = new TContext();         _repositories = new Dictionary<Type, object>();         _disposed = false;     }      public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class     {         if (_repositories.Keys.Contains(typeof(TEntity)))             return _repositories[typeof(TEntity)] as IRepository<TEntity>;          var repository = new Repository<TEntity>(_ctx);         _repositories.Add(typeof(TEntity), repository);         return repository;     }      public void Save()     {         _ctx.SaveChanges();     }      public void Dispose()     {         Dispose(true);         GC.SuppressFinalize(this);     }      protected virtual void Dispose(bool disposing)     {         if (!this._disposed)         {             if (disposing)             {                 _ctx.Dispose();             }              this._disposed = true;         }     } } 

ExampleService.cs

public class ExampleService {     private IRepository<Example> m_repo;      public ExampleService(IUnitOfWork uow)     {         m_repo = uow.GetRepository<Example>();     }      public void Add(Example Example)     {         m_repo.Add(Example);     }      public IEnumerable<Example> getAll()     {         return m_repo.All();     } } 

ExampleController.cs

public IEnumerable<Example> GetAll() {     // Create Unit Of Work object     IUnitOfWork uow = new UnitOfWork<AppDataContext>();      // Create Service with Unit Of Work attached to the DataContext     ExampleService service = new ExampleService(uow);      return service.getAll(); } 
like image 217
Gaui Avatar asked May 23 '13 14:05

Gaui


People also ask

Why do we use unit of work?

The unit of work class serves one purpose: to make sure that when you use multiple repositories, they share a single database context. That way, when a unit of work is complete you can call the SaveChanges method on that instance of the context and be assured that all related changes will be coordinated.

What is unit of work in MVC?

The Unit of Work pattern is used to group one or more operations (usually database CRUD operations) into a single transaction or “unit of work” so that all operations either pass or fail as one unit.

What is database work unit?

A unit of work is a recoverable sequence of operations within an application process. It is used by the database manager to ensure that a database is in a consistent state. Any reading from or writing to the database is done within a unit of work.

What is unit of work in Ado net?

The unit of work itself uses the interfaces defined in System. Data to be completely driver independent. That makes it quite easy to switch DB as long as you don't use anything but the SQL92 standard in your SQL statements. C# Shrink ▲ Copy Code.


1 Answers

Your ExampleService class is expecting IUnitOfWork, that means you just need another IUnitOfWork that is a Mock and its GetRepository() method will return an IRepository Mock.

For example (not really a Mock but In-Memory stub):

  public InMemoryRepository<T> : IRepository<T> where T : class   {         ........   }    public InMemoryUnitOfWork : IUnitOfWork   {        public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class        {             return new InMemoryRepository<TEntity>();        }   } 

Then:

public IEnumerable<Example> GetAll() {     // Create Unit Of Work object     IUnitOfWork uow = new InMemoryUnitOfWork();      // Create Service with Unit Of Work     ExampleService service = new ExampleService(uow);      return service.getAll(); } 
like image 88
haim770 Avatar answered Sep 17 '22 15:09

haim770