单位工作和放大器;通用库实体框架5 [英] Unit Of Work & Generic Repository with Entity Framework 5

查看:105
本文介绍了单位工作和放大器;通用库实体框架5的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用ASP.NET MVC 4与实体框架我把模型类和实体地图绘制现有表对这些模型类。这一切都是建立精细的伟大工程。

现在我想嘲笑这一点。我创建了一个需要DataContext的,并使用一个通用存储库组的工作。当我构建的服务能够在一次只需要具备的DataContext的一个实例得到许多仓库的数据。这也伟大工程。

现在的问题:我要测试的服务,以模拟数据。当我创建单位上班的实例中,我希望能够插入代替嘲笑真正的DataContext的一个DataContext。

我试图创建一个IContext接口,让真正的戏弄的DataContext实施,但遇到了与DbSet问题。我试图用IDbSet并创建FakeDbSet但没有成功。我也看到在互联网上的嘲讽与IDbSet的背景和使用FakeDbSet是个不错的办法。

你有什么想法,这将是实现这一目标的最佳途径?我现在已经是我想保留的行为,但真的希望能够在嘲笑在DataContext从Model类中的数据。

我知道,实体框架已经带有组的工作行为,你并不需要在此之上添加额外的行为。但我想换另一个类,跟踪所有存储库(称为类的UnitOfWork)的里面。

编辑:我写了两篇文章解释既LINQ和Entity Framework我的解决方案

<一个href=\"http://gaui.is/how-to-mock-the-datacontext-linq/\">http://gaui.is/how-to-mock-the-datacontext-linq/

<一个href=\"http://gaui.is/how-to-mock-the-datacontext-entity-framework/\">http://gaui.is/how-to-mock-the-datacontext-entity-framework/

下面是我的code:

IRepository.cs

 公共接口IRepository&LT; T&GT;其中T:类
{
    无效添加(T实体);
    无效删除(T实体);
    无效更新(T实体);
    ŧGetById(长ID);
    IEnumerable的&LT; T&GT;所有();
    IEnumerable的&LT; T&GT;查找(前pression&LT;&Func键LT; T,BOOL&GT;&GT; predicate);
}

IUnitOfWork.cs

  public接口IUnitOfWork:IDisposable接口
{
    IRepository&LT; TEntity&GT; GetRepository&LT; TEntity&GT;()其中TEntity:类;
    无效保存();
}

Repository.cs

 公共类资源库&LT; T&GT; :IRepository&LT; T&GT;其中T:类
{
    私人只读IDbContext _context;
    私人只读IDbSet&LT; T&GT; _dbset;    公共库(IDbContext上下文)
    {
        _context =背景;
        _dbset = context.Set&LT; T&GT;();
    }    公共虚拟无效添加(T实体)
    {
        _dbset.Add(实体);
    }    公共虚拟无效删除(T实体)
    {
        VAR进入= _context.Entry(实体);
        entry.State = System.Data.EntityState.Deleted;
    }    公共虚拟无效更新(T实体)
    {
        VAR进入= _context.Entry(实体);
        _dbset.Attach(实体);
        entry.State = System.Data.EntityState.Modified;
    }    公众实际的t GetById(长ID)
    {
        返回_dbset.Find(ID);
    }    公共虚拟IEnumerable的&LT; T&GT;所有()
    {
        返回_dbset;
    }    公共IEnumerable的&LT; T&GT;查找(前pression&LT;&Func键LT; T,BOOL&GT;&GT; predicate)
    {
        返回_dbset.Where(predicate);
    }
}

UnitOfWork.cs

 公共类的UnitOfWork&LT; TContext&GT; :IUnitOfWork哪里TContext:IDbContext,新的()
{
    私人只读IDbContext _ctx;
    私人字典&LT;类型,对象&gt; _repositories;
    私人布尔_disposed;    公众的UnitOfWork()
    {
        _ctx =新TContext();
        _repositories =新词典&LT;类型,对象&gt;();
        _disposed = FALSE;
    }    公共IRepository&LT; TEntity&GT; GetRepository&LT; TEntity&GT;()其中TEntity:类
    {
        如果(_repositories.Keys.Contains(typeof运算(TEntity)已))
            返回_repositories [typeof运算(TEntity)已作为IRepository&LT; TEntity取代;        变种库=新库&LT; TEntity&GT;(_ CTX);
        _repositories.Add(typeof运算(TEntity)已,库);
        返回库;
    }    公共无效保存()
    {
        _ctx.SaveChanges();
    }    公共无效的Dispose()
    {
        处置(真);
        GC.Sup pressFinalize(本);
    }    受保护的虚拟无效的Dispose(BOOL处置)
    {
        如果(!this._disposed)
        {
            如果(处置)
            {
                _ctx.Dispose();
            }            this._disposed = TRUE;
        }
    }
}

ExampleService.cs

 公共类ExampleService
{
    私人IRepository&所述;例&gt; m_repo;    公共ExampleService(IUnitOfWork UOW)
    {
        m_repo = uow.GetRepository&所述;例&gt;();
    }    公共无效添加(示例例)
    {
        m_repo.Add(例);
    }    公共IEnumerable的&lt;实施例&GT;得到所有()
    {
        返回m_repo.All();
    }
}

ExampleController.cs

 公开的IEnumerable&lt;例子&GT;得到所有()
{
    //工作对象的创建单位
    IUnitOfWork UOW =新的UnitOfWork&LT; AppDataContext&GT;();    //附加到DataContext工作单元创建服务
    ExampleService服务=新ExampleService(UOW);    返回service.getAll();
}


解决方案

ExampleService 类期待 IUnitOfWork ,这意味着你只需要另一个 IUnitOfWork 这是一个模拟及其 GetRepository()方法将返回 IRepository 模拟。

例如(不是一个真正的模拟,但在内存存根):

 公共InMemoryRepository&LT; T&GT; :IRepository&LT; T&GT;其中T:类
  {
        ........
  }  公共InMemoryUnitOfWork:IUnitOfWork
  {
       公共IRepository&LT; TEntity&GT; GetRepository&LT; TEntity&GT;()其中TEntity:类
       {
            返回新InMemoryRepository&LT; TEntity&GT;();
       }
  }

然后:

 公开的IEnumerable&lt;例子&GT;得到所有()
{
    //工作对象的创建单位
    IUnitOfWork UOW =新InMemoryUnitOfWork();    //与工作单元创建服务
    ExampleService服务=新ExampleService(UOW);    返回service.getAll();
}

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();
}

解决方案

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();
}

这篇关于单位工作和放大器;通用库实体框架5的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆