【问题标题】:Entity Framework ObjectContext re-usage实体框架 ObjectContext 重用
【发布时间】:2010-04-27 19:04:18
【问题描述】:

我现在正在学习 EF,有一个关于 ObjectContext 的问题:

当我访问数据库时,是否应该为每个查询(函数)创建 ObjectContext 的实例?

或者最好创建一次(单例)并重复使用?

在 EF 之前,我使用企业库数据访问块并为 DataAccess 函数创建了 dataacess 实例...

【问题讨论】:

  • IMO - 使用 DI 来解析 EF 对象上下文的实例并使用生命周期来检查哪个选项可以为您提供最佳结果...

标签: asp.net entity-framework


【解决方案1】:

我认为最常见的方式是根据请求使用它。开始创建它,做你需要的(大多数时候这些是需要公共ObjectContext的操作),最后dispose。大多数 DI 框架都支持这种情况,但您也可以使用 HttpModule 创建上下文并将其放置在 HttpContext.Current.Items 中。这是一个简单的例子:

public class MyEntitiesHttpModule : IHttpModule
{
    public void Init(HttpApplication application)
    {
        application.BeginRequest += ApplicationBeginRequest;
        application.EndRequest += ApplicationEndRequest;
    }

    private void ApplicationEndRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.Items[@"MyEntities"] != null)
            ((MyEntities)HttpContext.Current.Items[@"MyEntities"]).Dispose();
    }

    private static void ApplicationBeginRequest(Object source, EventArgs e)
    {
        var context = new MyEntities();
        HttpContext.Current.Items[@"MyEntities"] = context;
    }
}

【讨论】:

  • 我认为与在数据层中需要一个 ObjectContext 时简单地创建一个 ObjectContext 相比,这是一个更难维护的解决方案。我反对这个解决方案是你在你的 UI 层和你的数据层之间创建了一个不必要的依赖关系。如何与数据库通信是数据层的内部问题。其次,一开始似乎很容易不必担心延迟加载问题,但有一天你试图追踪一个错误并且无法确定哪里出了问题,因为你不知道导致延迟加载的数据在哪里错误已加载(根据经验..)
  • @rwwilden:抱歉,它是如何在 UI 和数据层之间创建依赖关系的?我正在使用存储库模式,并且存储库必须共享上下文。上下文由 DI 容器注入。请求并没有那么长,也没有太多会导致这么多问题的操作。如果你使用正确的模式,你不会有任何问题。
  • @rwwilden:在 SO 和其他页面上有数百万个关于 ObjectContext 重用的问题。每个请求的使用似乎占主导地位,这不仅仅是我的意见。
  • @LukLed 关于依赖。在你的 UI 层的某个地方你必须说:new MyEntities()。在我看来,您使用实体框架来访问数据这一事实是数据层的一个实现细节。
  • @SalvatorePreviti:在 http 请求期间保持上下文是完全可以的,但你不应该使用它比请求更长的时间,因为你可以完成使用过时的数据。
【解决方案2】:

绝对适用于每个查询。它是一个轻量级对象,因此每次需要时创建一个对象不会产生太多成本。

此外,您保持 ObjectContext 活动的时间越长,当您对它运行查询时,它所包含的缓存对象就越多。这可能会导致内存问题。因此,将 ObjectContext 作为单例是一个特别糟糕的主意。随着您的应用程序的使用,您会在单例 ObjectContext 中加载越来越多的实体,直到最终将整个数据库放入内存中(除非您在不再需要实体时分离它们)。

还有一个可维护性问题。有一天,您试图追踪一个错误,但无法确定导致该错误的数据加载位置。

【讨论】:

  • 如果唯一的选择是单例和访问时,我会同意这个答案。但是有一个完整的生命周期,其中一些可能会根据应用程序提供更好的性能。上下文缓存是有原因的 :) 每个请求是仅次于 on-access 的一堆中“最安全的”。
【解决方案3】:

不要使用单例。使用您的应用程序的每个人都会分享这一点,并且当该对象上下文跟踪实体时会发生各种疯狂的事情。

我会把它添加为私人成员

【讨论】:

  • 我的意思是每个会话单例(每个用户都有自己的),我打算禁用跟踪
  • 我同意 rwwilden 的第一反应。
【解决方案4】:

就像 Luke 说的,这个问题在 SO 上已经被问过很多次了。

对于 Web 应用程序,每个请求周期似乎效果最好。单例绝对是个坏主意。

每个请求都很好,因为一个网页有一个用户,也许是属于该用户的一些项目,也许是该用户的一些消息。您需要相同的 ObjectContext,因此您可以使用 User.Messages 来获取它们,也许将一些消息标记为已读,也许添加一个项目,然后在页面周期完成时提交或放弃整个对象图。

【讨论】:

  • 静态单例不仅是一个坏主意,也是非线程安全的!创建的上下文只能在一个线程中使用。
【解决方案5】:

这里迟到了 7 个月。我目前正在我的应用程序中解决这个问题,我倾向于通过在我的 HttpRequest 期间创建一个单例 ObjectContext 来使用@LukLed 解决方案。对于我的体系结构,我有几个用于构建页面的控件,这些控件都有自己的数据关注点,它们从 EF 层提取只读数据。他们每个人都创建和使用自己的 ObjectContext 似乎很浪费。此外,在少数情况下,一个控件可能会将数据拉入 Context 以供其他控件重用。例如,在我的母版页中,页面顶部的标题包含用户信息,页面上的其他控件可以重用这些信息。

我唯一担心的是我可能会将实体拉入会影响其他控件查询的上下文中。我还没有看到,但不知道我是否在自找麻烦。我想我们会看到的!

【讨论】:

    【解决方案6】:
    public class DBModel {
    
            private const string _PREFIX = "ObjectContext";
    
            // DBModel.GetInstance<EntityObject>();
            public static ObjectContext GetInstance<T>() {
                var key = CreateKey<T>();
                HttpContext.Current.Items[key] = HttpContext.Current.Items[key] ?? Activator.CreateInstance<T>();
                return HttpContext.Current.Items[key] as ObjectContext;
            }
    
            private static string CreateKey<T>() {
                return string.Format("{0}_{1}", _PREFIX, typeof(T).Name);
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 2013-11-26
      • 2013-03-07
      • 1970-01-01
      • 2011-07-30
      • 1970-01-01
      相关资源
      最近更新 更多