EF Core 的 DBContext 何时释放 Sql 连接?

3
使用经典的 ADO.NET 时,通常在执行完 SQL 命令后立即关闭 SQL 连接,因此该连接会被关闭并返回到池中。
类似于以下代码:
public Order[] GetActiveOrders()
{
        var orders = new List<Orders>();

        using (SqlConnection connection = new SqlConnection("connectionString"))
        {
            using (SqlCommand cmd = connection.CreateCommand())
            {
                cmd.CommandType = System.Data.CommandType.Text;
                cmd.CommandText = "Select * FROM ORDERS WHERE Status = 'Active'";
                cmd.Connection.Open();

                using (var reader = cmd.ExecuteReader())
                {
                    //populate orders
                }
            }
        }
        
        // SQL connection is closed here and returned back to connection pool
        
        return orders;
}

在使用EF Core的ASP.NET Core中,通常我们会使用依赖注入框架将DbContext注入到构造函数中。
      public class OrderService:IDisposable
      {
         private readonly MyDBContext _dbContext;
         
         public OrderService(MyDBContext dbContext)
         {
             _dbContext = dbContext;
         }
         
         public Order[] GetActiveOrders()
         {
             var orders = _dbContext.Orders.Where(x=>x.Status == 'Active').ToArray()
             return orders;
         }
         
         #region Dispose
         public void Dispose()
         {
              Dispose(true);
              GC.SuppressFinalize(this);
         }
    
         protected virtual void Dispose(bool disposing)
         {
              if (_disposed)
                  return;

              if (disposing)
              {
                  if (_dbContext != null)
                  {
                      _dbContext.Dispose();
                  }

                  // Free any other managed objects here.                    
              }

              // Free any unmanaged objects here.
              _disposed = true;
          }
      }
      

我假设在幕后,DbContext 仍然使用 SqlCommandSqlConnection 连接到数据库。
我想知道 EF Core 何时关闭 SqlConnection? 它是否在执行查询后立即关闭连接(类似于经典 ADO 中的方式),还是在 DbContext 被处理时关闭?
因此,在上面的示例中,它会在从 GetActiveOrders() 方法返回 Orders 之前处置连接,还是在 DI 容器处置 OrderService 时?

通常情况下,服务不应该处理它不拥有的资源,即通过构造函数注入的任何依赖项。 - Guru Stron
1个回答

3

附带说明:您不应处理不属于您的东西,这是 DI 注入的 DbContext(以及任何注入的对象)的情况。

但是回答你具体的问题。我找不到要链接到的文档,但只要您

  • 不通过 DbContextOptions 提供预分配的 DbConnection 对象
  • 不通过 .Database.OpenConnection 方法手动打开连接
  • 不通过 Database.BeginTransaction 方法打开显式事务

也就是说不要自己管理连接(在这种情况下,您负责关闭/处理),EF Core 仅在需要时打开连接,并立即在之后关闭它。

需要打开连接的情况是在 SaveChanges 中打开事务,直到提交或回滚为止。或者在执行返回查询的 DbReader 时打开连接,直到返回的读取器被使用或取消。换句话说,完全按照经典 ADO.NET 的做法。是的,在幕后它使用 ADO.NET(至少用于关系型数据库)。

一些额外信息可以在 Do I need to close the DbConnection manually when using ambient transactions with EF Core 2.1?Using EF Core to invoke stored procedure and closing connection 中找到。此外还有 连接弹性查询工作原理 等文档主题。


那么在GetActiveOrders()返回给调用者之前,连接应该被释放吗? - LP13
在您的示例中,它将在传递的IQueryableToArray方法调用GetEnumerator().MoveNext()(查询执行点)时打开。并且将在ToArray()完成后立即关闭它(完成使用返回的DbReader)。至于处理,我不确定,但肯定会关闭,这应该会将物理连接返回到池中。 - Ivan Stoev
EF Core 的内部代码类似于此 https://stackoverflow.com/questions/57283317/using-ef-core-to-invoke-stored-procedure-and-closing-connection/57287020#57287020,但是有更多的检查,并且在 ExecuteReader 中不会调用 close 直到打开的 reader 被关闭。因此不需要 Dispose - Ivan Stoev
微软明确表示:在使用后及时释放DbContext非常重要。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接