工作单位带有实体框架 5 的通用存储库 [英] Unit Of Work & Generic Repository with Entity Framework 5
问题描述
我将 ASP.NET MVC 4 与 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.
现在我想嘲笑这个.我创建了采用 DataContext 并使用通用存储库的工作单元.在此基础上,我构建了能够同时从多个存储库获取数据的服务,并且只需要一个 DataContext 实例.这也很好用.
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.
现在问题来了:我想用模拟数据测试服务.当我创建工作单元实例时,我希望能够插入一个模拟的 DataContext 而不是真正的 DataContext.
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.
我尝试创建一个 IContext 接口并让真实的和模拟的 DataContext 实现它,但遇到了 DbSet 的问题.我尝试使用 IDbSet 并创建 FakeDbSet 但没有成功.我还在互联网上读到使用 IDbSet 模拟上下文并使用 FakeDbSet 是一种糟糕的方法.
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.
您知道实现这一目标的最佳方法是什么吗?我现在拥有的是我想要保留的行为,但真的希望能够模拟来自 DataContext 中模型类的数据.
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.
我知道实体框架已经带有工作单元行为,您不需要在此之上添加额外的行为.但我想将它包装在另一个跟踪所有存储库的类(称为 UnitOfWork 类)中.
我写了两篇文章,解释了我使用 LINQ 和实体框架的解决方案.
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-实体框架/
这是我的代码:
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();
}
推荐答案
您的 ExampleService
类正在等待 IUnitOfWork
,这意味着您只需要另一个 IUnitOfWork
是一个 Mock,它的 GetRepository()
方法将返回一个 IRepository
Mock.
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.
例如(不是真正的 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>();
}
}
那么:
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();
}
这篇关于工作单位带有实体框架 5 的通用存储库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!