【问题标题】:MVC 4, EF 4.3 Managing context during the lifecycle of an Application RequestMVC 4、EF 4.3 在应用程序请求的生命周期中管理上下文
【发布时间】:2023-03-24 11:41:01
【问题描述】:

情况:我想做的是访问页面生命周期的数据上下文。这主要是为了 (a) 避免一系列 using() 并避免 (b) 访问延迟加载的属性时视图中出现超出范围的异常。

编辑:我正在使用 MVC 4 和 Entity Framework 4.3.1(最新)

我通常做的是

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

在我的控制器或数据层中。根据我的阅读,这样做的好处是它很干净,不会导致内存泄漏等。但缺点是即使在单个页面的生命周期中,我最终也会一次又一次地这样做,并且我的对象在视图,因为我已经处理了上下文。

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

Application_BeginRequest and EndRequest

但我只是不确定如何,以及有什么陷阱/最佳做法。

感谢您的帮助(如果可能,请提供一些代码示例!)

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 entity-framework entity-framework-4


    【解决方案1】:

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

    您应该实施像 http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application 这样的存储库方法

    无论如何,你真正需要做的就是在你的每个控制器上做这样的事情

    private MyDB b = null;
    public MyController()
    {
          b = new MyDB();
    }
    
    protected override void Dispose(bool disposing)
    {
          b.Dispose();
          base.Dispose(disposing);
    }
    

    【讨论】:

    • 谢谢 - 快速阅读了存储库方法,我认为这对我的应用程序来说可能有点过头了(至少在这一点上)。但是您对上下文的页面级访问的解决方案似乎简单而优雅!我会尝试并回来。
    • 我在一些较小的页面中添加了一个继承自它的 BaseController,并添加了此代码。做我需要的!
    • 我之前使用了建议的存储库和工作单元,但后来我放弃了它,因为它太多且不够通用。所以我建议你尝试让你自己的解决方案。
    • 存储库模式所有的东西!!不是。
    【解决方案2】:

    您希望使用数据上下文的方式绝对是禁忌(除非您要处理几百行数据库,在这种情况下为什么要使用 EF)。

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

    • 既然你提到使用延迟加载(我完全愿意 在服务器端切换)迟早你的所有数据库都会 被吞入内存(上下文级实体缓存)
    • 您的实体实例将在请求和线程之间共享(是的, 写操作为真)
    • EntitySet/DbSet 几乎是线程安全的
    • 您的写入操作将完全缓慢且不可预测,因为您将 将无法保存“只是您的更改”您将保存所有 自上次保存/提交更改以来已更改,您可能会保存其他线程 半生不熟的实体

    EF 上下文是 IDisposable 有一个很好的理由:它有望用于紧凑、短的操作,是的:你应该一直做 using(...) “事情”。

    如果您要构建一个供多人使用的网站、内联网解决方案等,上述所有内容都是一个问题。

    【讨论】:

    • 彼得 - 如果我的解释是正确的,你是说我目前的方法是好的方法(即我使用 using() 并在很短的时间内保持上下文)。我通过将范围保持在应用程序级别(例如作为单例)来理解缺点 - 但我并不是在暗示。为什么在单个页面请求的生命周期中保留上下文并在其结束时处理会非常糟糕?
    【解决方案3】:

    首先不要在视图中使用延迟加载(Entity Framework 转到数据库并一次将结果带回一行),因为来自视图的查询是不好的做法,会导致 Select N+1(Select N+1 是一种数据访问反模式,其中数据库以次优方式访问。)或类似的不良做法。

    使用多个对象上下文意味着每个请求使用多个数据库连接,从而导致数据库的额外压力和更慢的整体性能,而且每个对象上下文都不知道由另一个对象上下文跟踪的实体,并且可能必须再次查询数据库的当前状态或必须发出不必要的更新

    在编写视图时,您不必担心持久性或视图生成的查询数量。

    总结:

    1. 在操作中执行所有查询。

    2. 使用Include 方法强制对集合进行预先加载,以指定要包含在 初始查询。

    3. 每个请求使用一个对象上下文。

    问候

    【讨论】:

    • 非常有用的评论,谢谢。我已经开始在操作中执行 include() 来加载我需要的内容,并且我将我的上下文限制为每页请求 1 个,或者根据需要使用 using () 更短。
    【解决方案4】:

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

    using (MyDB b = new MyDB()) {
     ...do all my stuff
    
      return View(b.Data);
    }
    

    【讨论】:

    • 这不是真的。 return 关键字在右大括号之前这一事实并不意味着在客户端可以访问结果视图时它没有释放上下文...
    • 这不起作用。我确定我尝试过这个 - 在我可以访问我的视图中的属性之前,上下文确实被释放了。
    猜你喜欢
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 2019-01-22
    • 2011-09-15
    • 1970-01-01
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多