30

MVC 3 + EF 4.1在MVC中实例化和处理DbContext的最佳方式是什么?

我对付的DbContext两种方法之间进行选择:

  1. 实例化Application_BeginRequest,放入 HttpContext.Current.ItemsApplication_EndRequest处理。
  2. (为DbContext kindof包装)创建一次性的UnitOfWork并 开始using(var unitOfWork = new UnitOfWork()) { ... }

每个控制器动作分享您的体验,请:一个你会喜欢哪一种?每种方法有哪些优缺点?

+0

使用块方法有一些缺点。它会导致很多往返数据库和滥用Entity框架中的事务。请参阅http://ayende.com/blog/4775/new-profiler-feature-avoid-writes-from-multiple-sessions-in-the-same-request – marvelTracker

+0

为什么会导致更多往返?一个http请求应该在大多数情况下运行一个动作,所以如果你将整个动作的代码包装到这个使用块中,与第一种方法相比,不会有更多的数据库请求。 “每操作”方法的另一件事是,您应该始终注意数据库可能被调用的作用域并适当地放置该块。例如,如果您的模型包含一些要在一段时间视图渲染中加载的集合,则返回View(Model)的语句应该位于该块内部。 – YMC

+0

如果在控制器层中使用DbContext,则UnitOfWork会在UI层和数据库方法中创建强依赖关系。然后你需要一个服务层和存储库层。之后,如果您的存储库使用单独的UnitOfWork,并使用将成为问题的块。因为每个存储库都会创建事务和不必要的数据库往返。请参阅上面的链接了解更多详情如果你确定每个请求有一个服务调用,那么你可以在服务方法内部使用单元工作。但是,这不是保证。 – marvelTracker

回答

18

我会建议你使用依赖注入框架。您可以将DbContext为每个请求

container.RegisterType<MyDbContext>().InstancePerHttpRequest(); 

注册并注入它作为一个构造函数参数传递给控制器​​。

public class MyController : Controller 
{ 
    public MyController(MyDbContext myDbContext) 
    { 
     _myDbContext = myDbContext; 
    } 
} 

如果注册类型实现IDisposable则请求结束时的DI框架将它丢弃。

第一种方法:使用ID框架要比手动实现它清洁得多。进一步你的请求可能不需要你的UoW。

第二种方法:控制器不应该知道如何构建你的UoW(DbContext)。目的不是减少组件之间的耦合。

+0

对,使用IoC容器比处理BeginRequset和EndRequest更好,但它对我来说仍然非常接近数字1,这就是为什么我甚至没有将它作为单独的方法提取出来的原因。对我来说更重要的是比较2种访问和控制DbContext(=工作单元)生命周期的方式:第一种方式意味着ASP.NET/IoC基础设施负责它,第二种方式是关于每个控制器操作收费。 – YMC

+0

@YMC编辑答案。你的第二种方法将在你的控制器和UoW实现之间引入耦合。我建议你避免它。 – Eranga

+3

介绍服务层并向控制器注入服务。服务可以有许多存储库,并且存储库依赖于使用EFDbContext的UnitOfWork包装。然后使用DI来注入这些依赖关系。然后,您可以获得关注分离的优势。 – marvelTracker

-1
+2

OP没有说把DbContext放在一个静态字段中......他想把它放在HttpContext.Current.Items中,就我所见,这是非常安全的 –

+0

我没有说我把DbContext放到了global.asax中。我说我放置了实例化和配置DbContext的代码。 DbContext在HttpContext.Current.Items中。它是线程安全的。 – YMC

2

我们目前使用通过服务定位器从存储库工厂实例化的UoW(工作单元)注入的存储库。 Unity通过这种方式控制了你的工作。

您的具体实施将取决于如果您使用POCO的,实体对象等变化..

最终你想UOW如果你要在你的控制器不止一个对象集一起工作,以确保您只使用一个上下文。这将保持您的交易检查等。

如果你打算使用多个objectcontexts(即多个EDMX的),你会想看看使用UoW与MSDTC ...但这可能比你想知道的更多。最终,重要的是确保你实例化控制器操作所需的内容(即上下文的一个实例)。我不认为我会使用Begin_Request,你可能甚至不需要每个请求的上下文。

相关问题