2

我真的为 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 (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 类型,但这是事实。

  1. 问题是为什么会这样:为什么 EF 会在异常后自动释放资源(连接)?也许在 Microsoft 中,他们在处理异常和关闭连接方面比在纯 ADO.net 中做得更好?

  2. 为什么所有模式的例子都忽略了使用语句?

添加: >>对于您的最后一个示例,连接在您的第三行代码中打开和关闭

仅当您尝试访问 cxt.Items DbSet 时,才在连接池中创建连接,而不是之前和之后: 在此处输入图像描述 通过调用 Save 连接已经存在: 在此处输入图像描述 在此处输入图像描述 它们也存在并且在离开 Save 之后以及在抛出异常和测试方法之后有已离开: 在此处输入图像描述 并在程序停止工作后关闭: 在此处输入图像描述

4

1 回答 1

2

DbContext初始化时不打开连接。 DbContext为您执行的每个操作打开和关闭连接,例如。任何查询或调用SaveChanges.

如果要控制连接何时打开或关闭,则必须传递自己的连接并使用重载构造函数指定上下文拥有此连接:public DbContext(DbConnection existingConnection, bool contextOwnsConnection)

要回答您的问题,是的,您仍然需要使用using块或调用 Dispose 来释放任何非托管资源。请记住,EF 使用 ADO.NET,而这个在后台调用了许多非托管 API。

希望这可以帮助

更新:
为了验证所有这些,为您的上下文创建/添加一个新的构造函数:

public class TestDbContext : DbContext
{
  public TestDbContext(DbConnection connection, bool contextOwnsConnection)
    : base(connection, contextOwnsConnection) { }
}

然后在调用时使用您在示例中使用的相同代码SaveChanges()

var conn = new SqlConnection("your connection string here");
using (var ctx = new TestDbContext(conn, [false/true])) //play with true and false
{
  conn.Open(); //you can also comment this to discover other situations
  ctx.Items.Add(item);
  ctx.SaveChanges();
  throw new Exception(); //also comment this line and you will see the connection
                         //is still open because it is not controlled inside the 
                         //DbContext
}

如果您true在上下文构造函数中使用第二个参数,您会注意到测试完成后连接消失了。这是 DbContext 的默认行为,因为连接是在其中创建的,并且上下文拥有连接(根据需要打开和关闭)。

另一方面,如果您false使用conn.Open(). 如果上下文在conn.Open()内部调用以执行任何查询或保存更改,则上下文将控制何时打开和关闭连接。

您可以使用第二个布尔参数和调用conn.Open()来发现非常有趣的不同场景。

以下示例显示,即使您手动创建了连接,但由于您没有手动打开它,上下文也会自动打开和关闭。即使在引发异常并且您的本机连接仍处于打开状态之前,托管连接状态也已关闭。

var conn = new SqlConnection("your connection string here");
using (var ctx = new TestDbContext(conn, false)) 
{
  //conn.Open();
  ctx.Items.Add(item);
  ctx.SaveChanges();
  var state = conn.State
  throw new Exception();
}
于 2013-11-07T21:57:46.130 回答