ASP.NET MVC3和Entity Framework Code第一个架构

时间:2011-04-10 03:08:55

标签: asp.net-mvc unit-testing entity-framework architecture code-first

My previous question让我再次思考层,存储库,依赖注入和这样的架构。

我的架构现在看起来像这样:
我首先使用EF代码,所以我只创建了POCO类和上下文。这创建了数据库和模型 级别更高的是业务层类(提供者)。我为每个域使用不同的提供程序...比如MemberProvider,RoleProvider,TaskProvider等。我在每个提供程序中创建了我的DbContext的新实例。
然后我在我的控制器中实例化这些提供程序,获取数据并将它们发送到Views。

我的初始架构包括存储库,我已经摆脱了因为我被告知它只会增加复杂性,所以为什么我不仅仅使用EF。我想这样做..直接从控制器使用EF,但我必须编写测试,它与真正的数据库有点复杂。我不得不假装 - 以某种方式模拟数据。因此,我为每个提供商创建了一个接口,并使列表中的硬编码数据成为假提供者。有了这个,我回到了一些地方,我不知道如何正确地进行。

这些事情开始过于复杂化......许多方法和“模式”......它产生了太多的噪音和无用的代码。

是否有任何SIMPLE和可测试的体系结构用于使用Entity Framework创建和ASP.NET MVC3应用程序?

4 个答案:

答案 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://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/678b5871-bec5-4640-a024-71bd4d5c77ff

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个非常好的博客帖子支持。值得一试。并且,不要放弃存储库..但是。