【问题标题】:Should Entity Framework Context be Put into Using Statement?是否应该将实体框架上下文放入 Using 语句中?
【发布时间】:2014-05-05 08:28:58
【问题描述】:

实体框架上下文对象实现了一个 Dispose() 方法,该方法“释放对象上下文使用的资源”。它的真正作用是什么?总是把它放在 using {} 语句中会是一件坏事吗?我已经看到它在有和没有 using 语句的情况下都被使用。

我将专门从 WCF 服务方法中使用 EF 上下文,创建上下文,执行一些 linq 并返回答案。

编辑:似乎我不是唯一对此感到疑惑的人。另一个问题是 Dispose() 方法中真正发生了什么。有人说它会关闭连接,而有些文章则说不会。有什么关系?

【问题讨论】:

    标签: c# entity-framework


    【解决方案1】:

    如果你创建了一个上下文,你必须在以后释放它。是否应该使用using 语句取决于上下文的生命周期。

    1. 如果您在方法中创建上下文并仅在该方法中使用它,您应该真正使用using 语句,因为它无需任何额外代码即可为您提供异常处理。

    2. 如果你使用上下文的时间更长——也就是说生命周期不受方法执行时间的限制——你不能使用using语句,你必须自己调用Dispose()小心你总是叫它。

    Dispose()对对象上下文有什么作用?

    我没有看代码,但至少我希望它关闭与其底层套接字或传输机制使用的任何资源的数据库连接。

    【讨论】:

      【解决方案2】:

      Per Progamming Entity Framework:“您可以显式处置 ObjectContext 或等待垃圾收集器完成这项工作。”

      因此,简而言之,虽然不需要 using 语句,但最好的做法是,如果您知道已完成使用 ObjectContext,因为资源会立即释放,而不是等待垃圾回收。

      【讨论】:

      • GC 的目的是明确地处理事情。必须(如果可能)处置引用非托管资源的对象。所以这里真正的问题 - EF 上下文是否引用了非托管资源?如果没有,那么你不应该处理它......
      【解决方案3】:

      由于您不知道垃圾收集器何时处置项目,因此如果您知道何时完成,最好将实现 IDisposable 的对象包装在 using-block 中。

      【讨论】:

        【解决方案4】:

        EF5 及之前的版本

            using { ...
                    // connecction open here.
        
                    ...
                    context.Blogs.Add(blog); 
                    context.SaveChanges();   // query etc now opens and immediately closes 
        
                    ...
                    context.Blogs.Add(blog); 
                    context.SaveChanges();   // query etc now opens and immediately closes 
           }
        

        EF6 及以后版本

         using {
                // connecction open here.
        
                ...
                context.Blogs.Add(blog); 
                context.SaveChanges(); 
        
                // The underlying store connection remains open for the next operation  
        
                ...
                context.Blogs.Add(blog); 
                context.SaveChanges(); 
        
                // The underlying store connection is still open 
        
           } // The context is disposed – so now the underlying store connection is closed
        

        参考:http://msdn.microsoft.com/en-us/data/dn456849#open5

        【讨论】:

        • 这是错误的或具有误导性的。您引用的文章是关于管理连接的,关于手动调用connection.Open()(并且您不会将其转换为示例代码),而不是关于Dispose()。如果您不手动调用 connection.Open()(将其留给 EF 连接管理),则连接将在您的 // The underlying store connection is still open 处关闭。与OP问题无关。
        【解决方案5】:

        始终,如果您实例化一个实现 IDisposable 的类,那么您有责任在其上调用 Dispose。除了一种情况,这意味着一个 using 块。

        【讨论】:

        • 没错,但问题是 Dispose() 方法对 EF 上下文的作用。从我能找到的关于该主题的内容来看,这似乎并不真正重要!
        • 感谢您提出这个问题。结果,我发现我担心在我们的应用程序中忘记的所有 Dispose 调用可能没有我担心的那么重要(通过阅读 lee.hdgreetings.com/2008/06/linq-datacontex.html)。
        • 虽然我使用的是 DataContext,但我认为 EF 也会跟踪对象更改,这在这两种情况下可能是更大的资源。
        • 我刚刚快速浏览了 DataContext 类,引用的文章似乎完全错误 - DataContext.Dispose() 尝试关闭底层连接。 (可能是我错了,连接通常是关闭的,但至少它会尝试关闭它。而且我无法想象 LINQ to SQL 会因为性能影响而为每个请求创建一个新连接,所以我倾向于相信连接将在数据上下文处于活动状态时打开。)
        • @Johan:今天做什么都没关系。这不是你的代码。明天可能会改变。鉴于您依赖于今天的实施,它可能应该明天改变,只是为了教你为什么不!
        【解决方案6】:

        当您处置时,ObjectContext 会处置其他拥有的对象。

        包括包装实际数据库连接的 EntityConnection 之类的东西,即通常是 SqlConnection。

        所以“如果”SqlConnection 是打开的,它将在您处理 ObjectContext 时关闭。

        【讨论】:

          【解决方案7】:

          我真的为 ADO.net 和 EF v.6 测试了这个东西,并观察了 SQL 表中的连接

          select * from sys.dm_exec_connections
          

          要测试的方法如下所示:

          1) 使用 ADO.net

            using(var Connection = new SqlConnection(conString))
            {
              using (var command = new SqlCommand(queryString, Connection))
              {    
                 Connection.Open();
                 command.ExecuteNonQueryReader();
                 throw new Exception()  // Connections were closed after unit-test had been 
                 //finished.  Expected behaviour
               }
            }
          

          2) ADO.net 不使用

          var Connection = new SqlConnection(conString);
          using (var command = new SqlCommand(queryString, Connection))
          {
              Connection.Open();
               command.ExecuteNonQueryReader();
              throw new Exception() // Connections were NOT closed after unit-test had been finished
          
               finished.  I closed them manually via SQL.  Expected behaviour
              }
          

          1) EF 与 using。

           using (var ctx = new TestDBContext())
              {
                  ctx.Items.Add(item);
                  ctx.SaveChanges();
                  throw new Exception() // Connections were closed, as expected.
          
               }
          

          2) EF 不使用

           var ctx = new TestDBContext();             
           ctx.Items.Add(item);
           ctx.SaveChanges();
           throw new Exception() // Connections WERE successfully closed, as NOT expected.
          

          我不知道为什么会这样,但是 EF 自动关闭了连接。此外,所有使用 EF 的存储库和 UnitOfWork 模式都不使用 using。这对我来说很奇怪,因为 DBContext 是 Disposable 类型,但这是事实。

          也许在微软他们做了一些新的处理?

          【讨论】:

          • 其实很简单:如果您不手动打开连接(如ctx.Database.Connection.Open();),EF6 会处理它,并将在每次查询时管理打开/关闭(请参阅 ADO 连接池为什么这不是一个坏主意)。但是如果你手动打开它,EF6 会认为你知道你在做什么并保持打开状态。
          • 你没有回答我评论的主题。 EF 没有手动打开的连接。代码中的 cmets 中的所有粘合
          【解决方案8】:

          我注意到(尽管仅在一个应用程序中)显式处理导致 mscorlib 中的线程中止异常在应用程序代码之前被捕获,但至少在我的情况下会导致明显的性能损失。尚未对此问题进行任何重大研究,但如果您这样做,可能值得考虑。只需观察您的 DEBUG 输出,看看您是否得到相同的结果。

          【讨论】:

            【解决方案9】:

            如果 Dispose 关闭与 DB 的连接,那么调用它是个坏主意。 例如,在 ADO.NET 中,连接位于连接池中,并且在超时或应用程序池停止之前永远不会关闭。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-10-27
              • 1970-01-01
              • 2013-08-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多