Asp.net mvc MVC 4,EF 4.3在应用程序请求的生命周期中管理上下文

Asp.net mvc MVC 4,EF 4.3在应用程序请求的生命周期中管理上下文,asp.net-mvc,asp.net-mvc-3,entity-framework,entity-framework-4,Asp.net Mvc,Asp.net Mvc 3,Entity Framework,Entity Framework 4,情境:我想做的是访问页面生命周期的数据上下文。这主要是为了避免在访问延迟加载的属性时在视图中出现一系列使用和范围外异常 编辑:我正在使用最新的MVC4和EntityFramework 4.3.1 我通常做的是 using (MyDB b = new MyDB()) { ...do all my stuff } 在我的控制器或数据层中。根据我的阅读,这样做的好处是它干净,不会导致内存泄漏等。但缺点是,即使在单个页面的生命周期中,我也会一次又一次地这样做,并且我的对象在视图中丢失了上下文,因为我

情境:我想做的是访问页面生命周期的数据上下文。这主要是为了避免在访问延迟加载的属性时在视图中出现一系列使用和范围外异常

编辑:我正在使用最新的MVC4和EntityFramework 4.3.1

我通常做的是

using (MyDB b = new MyDB()) {
 ...do all my stuff
}
在我的控制器或数据层中。根据我的阅读,这样做的好处是它干净,不会导致内存泄漏等。但缺点是,即使在单个页面的生命周期中,我也会一次又一次地这样做,并且我的对象在视图中丢失了上下文,因为我已经处理了上下文

我读了一些书,发现2009年有一篇类似的帖子,但答案中没有代码。当然,其他一些人已经想出了解决这个问题的办法——我想我必须要做点什么

Application_BeginRequest and EndRequest
但我只是不确定如何进行,以及最佳实践是什么


如果可能的话,感谢您对一些代码示例的帮助

我看到您有一个asp.net MVC标记,所以我假设您正在使用它

您应该实现一种存储库方法,如

不管怎样,你真正需要做的就是在你的每个控制器上做类似的事情

private MyDB b = null;
public MyController()
{
      b = new MyDB();
}

protected override void Dispose(bool disposing)
{
      b.Dispose();
      base.Dispose(disposing);
}

我看到您有一个asp.net MVC的标记,所以我假设您正在使用它

您应该实现一种存储库方法,如

不管怎样,你真正需要做的就是在你的每个控制器上做类似的事情

private MyDB b = null;
public MyController()
{
      b = new MyDB();
}

protected override void Dispose(bool disposing)
{
      b.Dispose();
      base.Dispose(disposing);
}

除非您要处理几百行的数据库,否则您希望使用datacontext的方式是绝对不可能的,在这种情况下,为什么要使用EF呢

但是,如果您有一个实际生产规模的数据库,将上下文固定到应用程序范围将导致以下结果:

既然您提到使用懒散加载功能,我完全可以 服务器端的切换迟早都会影响数据库 将上下文级实体缓存拖到内存中 您的实体实例将在请求和线程之间共享是, 对于写操作,为true EntitySet/DbSet几乎是线程安全的 您的写操作将非常缓慢,而且不可预测,因为您将 无法仅保存您的更改,您将保存所有更改 自上次保存/提交更改以来已更改,您可能会保存其他线程 还有半生不熟的实体 EF上下文是IDisposable的,有一个很好的理由:它预计将用于紧凑、简短的操作,是的:您应该使用。。。一直都是这样


如果您正在构建一个网站、内部网解决方案等,并且将由多人使用,则上述所有内容都是一个问题。

您希望使用datacontext的方式是绝对不可能的,除非您正在处理几百行数据库,在这种情况下,为什么要使用EF呢

但是,如果您有一个实际生产规模的数据库,将上下文固定到应用程序范围将导致以下结果:

既然您提到使用懒散加载功能,我完全可以 服务器端的切换迟早都会影响数据库 将上下文级实体缓存拖到内存中 您的实体实例将在请求和线程之间共享是, 对于写操作,为true EntitySet/DbSet几乎是线程安全的 您的写操作将非常缓慢,而且不可预测,因为您将 无法仅保存您的更改,您将保存所有更改 自上次保存/提交更改以来已更改,您可能会保存其他线程 还有半生不熟的实体 EF上下文是IDisposable的,有一个很好的理由:它预计将用于紧凑、简短的操作,是的:您应该使用。。。一直都是这样


如果您正在建立网站、内部网解决方案,etc将由多人使用。

首先,不要使用延迟加载实体框架进入数据库,并在视图中一次返回一行结果,因为来自视图的查询是错误的做法,并导致选择N+1。选择N+1是一种数据访问反模式,其中以次优方式访问数据库。或类似的不良行为

使用多个对象上下文意味着每个请求使用多个数据库连接,这会对数据库造成额外的压力,降低总体性能。此外,每个对象上下文都不知道由其他对象上下文跟踪的实体,可能需要再次查询数据库的当前状态,或者需要发出不必要的更新

在编写视图时,您不应该考虑持久性或视图生成的查询数量

总结:

执行操作中的所有查询

使用Include方法强制立即加载集合,以指定要在集合中包含的对象模型片段 初始查询

每个请求使用一个对象上下文 .
首先,不要使用延迟加载实体框架进入数据库,并在视图中一次返回一行结果,因为来自视图的查询是错误的做法,并且导致选择N+1。选择N+1是一种数据访问反模式,其中以次优方式访问数据库。或类似的不良行为

使用多个对象上下文意味着每个请求使用多个数据库连接,这会对数据库造成额外的压力,降低总体性能。此外,每个对象上下文都不知道由其他对象上下文跟踪的实体,可能需要再次查询数据库的当前状态,或者需要发出不必要的更新

在编写视图时,您不应该考虑持久性或视图生成的查询数量

总结:

执行操作中的所有查询

使用Include方法强制立即加载集合,以指定要在集合中包含的对象模型片段 初始查询

每个请求使用一个对象上下文。
关于

您可以在退出using块之前返回,以便在视图中延迟加载时上下文将在范围内

using (MyDB b = new MyDB()) {
 ...do all my stuff

  return View(b.Data);
}

您可以在退出using块之前返回,以便在视图中延迟加载时上下文将在范围内

using (MyDB b = new MyDB()) {
 ...do all my stuff

  return View(b.Data);
}

彼得-如果我的解释正确,你是说我目前的方法是好的,也就是说,我使用并在很短的时间内保持上下文。我通过将作用域保持在应用程序级别(例如作为一个单例)来理解其缺点,但我并不是建议这样做。为什么在单页请求的生命周期中保留上下文并在请求结束时进行处理会非常糟糕?Peter-如果我的解释正确,你是说我当前的方法是好的,即我使用并在很短的时间内保留上下文。我通过将作用域保持在应用程序级别(例如作为一个单例)来理解其缺点,但我并不是建议这样做。为什么在单个页面请求的生命周期中保留上下文并在请求结束时进行处理会非常糟糕?谢谢-我快速阅读了存储库方法,我认为至少在这一点上对我的应用程序来说,这可能是一种过分的做法。但是您的页面级上下文访问解决方案似乎简单而优雅!我在一些较小的页面中添加了一个从中继承的BaseController,并添加了以下代码。做我需要的!我以前使用过建议的存储库和工作单元,但后来我放弃了它,因为它太多,不够通用。所以我建议你试着做你自己的解决方案。存储库模式所有的事情!!不用了。谢谢——我快速阅读了存储库方法,我认为至少在这一点上,这对我的应用程序来说可能是一种过度使用。但是您的页面级上下文访问解决方案似乎简单而优雅!我在一些较小的页面中添加了一个从中继承的BaseController,并添加了以下代码。做我需要的!我以前使用过建议的存储库和工作单元,但后来我放弃了它,因为它太多,不够通用。所以我建议你试着做你自己的解决方案。存储库模式所有的事情!!不是。非常有用的评论,谢谢。我已经开始在操作中添加我需要的内容,并且我将我的上下文限制为每页请求1个,或者根据需要使用更短的内容。非常有用的评论,谢谢。我已经开始在动作中包含我需要的内容,并且我将我的上下文限制为每页请求1个,或者根据需要使用更短的内容。这不是真的。return关键字位于右大括号之前的事实并不意味着在客户端可以访问结果视图时它没有处理上下文…这不起作用。我确信我已经尝试过了——在我可以访问视图中的属性之前,上下文确实被处理掉了。但事实并非如此。return关键字位于右大括号之前的事实并不意味着在客户端可以访问结果视图时它没有处理上下文…这不起作用。我确信我已经尝试过了——在我可以访问视图中的属性之前,上下文确实被处理掉了。