My previous question让我再次思考层,存储库,依赖注入和这样的架构。
我的架构现在看起来像这样:
我首先使用EF代码,所以我只创建了POCO类和上下文。这创建了数据库和模型
级别更高的是业务层类(提供者)。我为每个域使用不同的提供程序...比如MemberProvider,RoleProvider,TaskProvider等。我在每个提供程序中创建了我的DbContext的新实例。
然后我在我的控制器中实例化这些提供程序,获取数据并将它们发送到Views。
我的初始架构包括存储库,我已经摆脱了因为我被告知它只会增加复杂性,所以为什么我不仅仅使用EF。我想这样做..直接从控制器使用EF,但我必须编写测试,它与真正的数据库有点复杂。我不得不假装 - 以某种方式模拟数据。因此,我为每个提供商创建了一个接口,并使列表中的硬编码数据成为假提供者。有了这个,我回到了一些地方,我不知道如何正确地进行。
这些事情开始过于复杂化......许多方法和“模式”......它产生了太多的噪音和无用的代码。
是否有任何SIMPLE和可测试的体系结构用于使用Entity Framework创建和ASP.NET MVC3应用程序?
答案 0 :(得分:93)
答案 1 :(得分:13)
使用存储库模式是否会增加复杂性?在你的场景中,我不这么认为。它使TDD更容易,您的代码更易于管理。尝试使用Generic存储库模式以获得更多分离和更清晰的代码。
如果您想了解有关实体框架中TDD和设计模式的更多信息,请查看:http://msdn.microsoft.com/en-us/ff714955.aspx
然而,您似乎正在寻找模拟测试实体框架的方法。一种解决方案是使用虚拟种子方法生成有关数据库初始化的数据。在http://blogs.msdn.com/b/adonet/archive/2010/09/02/ef-feature-ctp4-dbcontext-and-databases.aspx
上查看种子部分您也可以使用一些模拟框架。我所知道的最着名的是:
要查看更完整的.NET模拟框架列表,请查看:https://stackoverflow.com/questions/37359/what-c-mocking-framework-to-use
另一种方法是使用像SQLite这样的内存数据库提供程序。在Is there an in-memory provider for Entity Framework?
了解更多信息最后,这里有一些关于单元测试实体框架的好链接(有些链接指的是实体框架4.0。但你会明白这一点。):
http://mosesofegypt.net/post/Introducing-Entity-Framework-Unit-Testing-with-TypeMock-Isolator.aspx
What is the way to go to fake my database layer in a unit test?
答案 2 :(得分:2)
我所做的是使用一个简单的ISession和EFSession对象,在我的控制器中易于模拟,易于使用Linq和强类型访问。使用Ninject注入DI。
public interface ISession : IDisposable
{
void CommitChanges();
void Delete<T>(Expression<Func<T, bool>> expression) where T : class, new();
void Delete<T>(T item) where T : class, new();
void DeleteAll<T>() where T : class, new();
T Single<T>(Expression<Func<T, bool>> expression) where T : class, new();
IQueryable<T> All<T>() where T : class, new();
void Add<T>(T item) where T : class, new();
void Add<T>(IEnumerable<T> items) where T : class, new();
void Update<T>(T item) where T : class, new();
}
public class EFSession : ISession
{
DbContext _context;
public EFSession(DbContext context)
{
_context = context;
}
public void CommitChanges()
{
_context.SaveChanges();
}
public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class, new()
{
var query = All<T>().Where(expression);
foreach (var item in query)
{
Delete(item);
}
}
public void Delete<T>(T item) where T : class, new()
{
_context.Set<T>().Remove(item);
}
public void DeleteAll<T>() where T : class, new()
{
var query = All<T>();
foreach (var item in query)
{
Delete(item);
}
}
public void Dispose()
{
_context.Dispose();
}
public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class, new()
{
return All<T>().FirstOrDefault(expression);
}
public IQueryable<T> All<T>() where T : class, new()
{
return _context.Set<T>().AsQueryable<T>();
}
public void Add<T>(T item) where T : class, new()
{
_context.Set<T>().Add(item);
}
public void Add<T>(IEnumerable<T> items) where T : class, new()
{
foreach (var item in items)
{
Add(item);
}
}
/// <summary>
/// Do not use this since we use EF4, just call CommitChanges() it does not do anything
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item"></param>
public void Update<T>(T item) where T : class, new()
{
//nothing needed here
}
如果我想从EF4切换到让我们说MongoDB,我只需要制作一个实现ISession的MongoSession ......
答案 3 :(得分:1)
我在决定MVC应用程序的一般设计时遇到了同样的问题。 Shiju Varghese的This CodePlex项目得到了很多帮助。它在ASP.net MVC3,EF CodeFirst中完成,并且还使用服务层和存储库层。依赖注入是使用Unity完成的。它很简单,很容易理解。它还有4个非常好的博客帖子支持。值得一试。并且,不要放弃存储库..但是。