Asp.net-Mvc-4

使用 Entity Framework 5 的工作單元和通用儲存庫

  • May 23, 2013

我將 ASP.NET MVC 4 與 Entity Framework 5 一起使用。我有模型類和實體映射來將現有表映射到這些模型類。所有這些設置都很好,效果很好。

現在我想嘲笑這個。我創建了採用 DataContext 並使用通用儲存庫的工作單元。在那之後,我建構了能夠一次從許多儲存庫中獲取數據的服務,並且只需要一個 DataContext 實例。這也很好用。

**現在問題來了:**我想用模擬數據測試服務。當我創建工作單元實例時,我希望能夠插入一個模擬的 DataContext 而不是真正的 DataContext。

我試圖創建一個 IContext 介面並讓真實的和模擬的 DataContext 實現它,但遇到了 DbSet 的問題。我嘗試使用 IDbSet 並創建 FakeDbSet 但沒有成功。我還在網際網路上讀到使用 IDbSet 模擬上下文並使用 FakeDbSet 是一種不好的方法。

您知道實現這一目標的最佳方法是什麼嗎?我現在擁有的是我想保留的行為,但真的希望能夠模擬來自 DataContext 中的模型類的數據。

我知道實體框架已經帶有工作單元行為,並且您不需要在此之上添加額外的行為。但我想將它包裝在另一個跟踪所有儲存庫的類(稱為 UnitOfWork 類)中。

**編輯:**我寫了兩篇文章來解釋我使用 LINQ 和實體框架的解決方案。

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

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

這是我的程式碼:

IRepository.cs

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

IUnitOfWork.cs

public interface IUnitOfWork : IDisposable
{
   IRepository&lt;TEntity&gt; GetRepository&lt;TEntity&gt;() where TEntity : class;
   void Save();
}

儲存庫.cs

public class Repository&lt;T&gt; : IRepository&lt;T&gt; where T : class
{
   private readonly IDbContext _context;
   private readonly IDbSet&lt;T&gt; _dbset;

   public Repository(IDbContext context)
   {
       _context = context;
       _dbset = context.Set&lt;T&gt;();
   }

   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&lt;T&gt; All()
   {
       return _dbset;
   }

   public IEnumerable&lt;T&gt; Find(Expression&lt;Func&lt;T, bool&gt;&gt; predicate)
   {
       return _dbset.Where(predicate);
   }
}

UnitOfWork.cs

public class UnitOfWork&lt;TContext&gt; : IUnitOfWork where TContext : IDbContext, new()
{
   private readonly IDbContext _ctx;
   private Dictionary&lt;Type, object&gt; _repositories;
   private bool _disposed;

   public UnitOfWork()
   {
       _ctx = new TContext();
       _repositories = new Dictionary&lt;Type, object&gt;();
       _disposed = false;
   }

   public IRepository&lt;TEntity&gt; GetRepository&lt;TEntity&gt;() where TEntity : class
   {
       if (_repositories.Keys.Contains(typeof(TEntity)))
           return _repositories[typeof(TEntity)] as IRepository&lt;TEntity&gt;;

       var repository = new Repository&lt;TEntity&gt;(_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;
       }
   }
}

範例服務.cs

public class ExampleService
{
   private IRepository&lt;Example&gt; m_repo;

   public ExampleService(IUnitOfWork uow)
   {
       m_repo = uow.GetRepository&lt;Example&gt;();
   }

   public void Add(Example Example)
   {
       m_repo.Add(Example);
   }

   public IEnumerable&lt;Example&gt; getAll()
   {
       return m_repo.All();
   }
}

ExampleController.cs

public IEnumerable&lt;Example&gt; GetAll()
{
   // Create Unit Of Work object
   IUnitOfWork uow = new UnitOfWork&lt;AppDataContext&gt;();

   // Create Service with Unit Of Work attached to the DataContext
   ExampleService service = new ExampleService(uow);

   return service.getAll();
}

你的ExampleService類是期待IUnitOfWork的,這意味著你只需要另一個IUnitOfWork是 Mock 並且它的GetRepository()方法將返回一個IRepositoryMock。

例如(不是真正的 Mock,而是 In-Memory 存根):

 public InMemoryRepository&lt;T&gt; : IRepository&lt;T&gt; where T : class
 {
       ........
 }

 public InMemoryUnitOfWork : IUnitOfWork
 {
      public IRepository&lt;TEntity&gt; GetRepository&lt;TEntity&gt;() where TEntity : class
      {
           return new InMemoryRepository&lt;TEntity&gt;();
      }
 }

然後:

public IEnumerable&lt;Example&gt; GetAll()
{
   // Create Unit Of Work object
   IUnitOfWork uow = new InMemoryUnitOfWork();

   // Create Service with Unit Of Work
   ExampleService service = new ExampleService(uow);

   return service.getAll();
}

引用自:https://stackoverflow.com/questions/16716527