2011-03-05 38 views
7

在使用MVC应用程序时管理实体框架上下文的最佳方式是什么?EF上下文管理

我正在使用存储库/服务模式。

编辑

通过其中的一些问题细算:stackoverflow.com/users/587920/sam-striano,我更糊涂了,然后前。有人说每个存储库使用上下文,但是如果我想在一个控制器方法中使用多个存储库,

为了遵循良好的分离设计,您如何在MVC应用程序中使用UnitOfWork,使其不依赖于EF?我希望能够使用模拟环境对我的控制器,模型,服务等进行单元测试?

+0

此讨论的许多倍。例如,我推荐你从上周的用户提出的问题:http://stackoverflow.com/users/587920/sam-striano然后问你发现的具体问题。 – 2011-03-05 18:12:53

+0

@Lad - 请参阅我的编辑。 – Andrew 2011-03-05 18:28:08

+0

这是一个很好的帖子,显示了EF Code First Repository Patter的代码,其中包含一个工作单元。它使用Structuremap作为IoC并具有所有内容的代码示例。 http://stackoverflow.com/questions/4442828/entity-framework-4-ctp-4-ctp-5-generic-repository-pattern-and-unit-testable – Paul 2011-03-05 22:18:00

回答

6

使用依赖注入控制框架/反转,如:

  1. Ninject
  2. Autofac
  3. StructureMap
  4. 统一

使用IoC容器,你可以告诉它如何管理单个数据上下文(最常见的是每个请求)。当您为每个请求设置数据上下文时,容器会自动奇迹般地为每个请求提供需要数据上下文相同数据上下文的任何类。

这是关于设置Ninject的good article

你的代码将最有可能最终看起来像,假设你使用一个通用存储库:

Ninject模块:

public class NinjectRegistrationModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<MyDataContext>().ToSelf().InRequestScope(); 
     Bind(typeof(RepositoryImplementation<>)).ToSelf().InRequestScope(); 

    } 
} 

通用存储库:

public RepositoryImplementation<T> : IRepository<T> where T : class 
{ 
    MyDataContext _dataContext; 

    public RepositoryImplementation<T>(MyDataContext dataContext) 
    { 
     _dataContext = dataContext; 
    } 

    // bunch of methods that utilize _dataContext 
} 

服务类别:

public class MyServiceClass 
{ 
    IRepository<SomeEntity> _someEntityRepository; 

    public MyServiceClass(IRepository<SomeEntity> someEntityRepository) 
    { 
     _someEntityRepository = someEntityRepository; 
    } 

    // do stuff with _someEntityRepository = someEntityRepository; 
} 

控制器:

public class MyController 
{ 
    MyServiceClass _myServiceClass; 

    public MyController(MyServiceClass myServiceClass) 
    { 
     // Ninject will auto-magically give us a myServiceClass 
     // which will Ninject will inject a repository into MyServiceClass's constructor 
     _myServiceClass = myServiceClass; 
    } 

    public ActionResult MyAction() 
    { 
     // use _myServiceClass to do stuff 
     return View(); 
    } 
} 
+0

我喜欢直接投资,但您仍应该从存储库中实例化ObjectContext。例如,考虑由IoC容器配置为单例的存储库的后果,并接收ObjectContext作为构造函数参数。 – smartcaveman 2011-03-05 20:41:44

+0

伟大的职位,谢谢!但我有几个问题。 1)在Ninject Bind示例中,我使用EF4,您从哪里获取Bind ()。ToSelf()。InRequestScope();)的上下文。 MVC应用程序不应该知道EF,对吗? – Andrew 2011-03-05 23:28:54

+0

您是否尝试将Ninject模块放入您的服务层,并将其引用到您的ASP.NET MVC项目中? – Omar 2011-03-05 23:49:33

0

如果您的功能很简单,那么您应该在每个存储库中创建一个新的ObjectContext。实例化它们很便宜。

如果这样会产生冲突,您可以按照评论中的建议使用工作单元模式。

我建议你在将ObjectContext或DataContext与DI容器集成时非常谨慎。许多人在默认情况下并未在其生命周期中使用适当的范围。

+0

每个存储库有一个新的上下文是只适用于简单的场景。您通常会发现您想要在多个存储库之间共享上下文。这通常通过使用UnitOfWork模式来处理。 – 2011-03-05 18:14:32

+0

UnitOfWork模式的任何好例子? – Andrew 2011-03-05 18:22:03

+0

http://martinfowler.com/eaaCatalog/unitOfWork.html – smartcaveman 2011-03-05 18:26:59