Question

I realy tested this thing for both ADO.net and EF v.6 and watched connections in SQL table

select * from sys.dm_exec_connections

Methods to be tested looked like this:

1) ADO.net with using

  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 withour using

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 with using.

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

     }

2) EF without using

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

I don't know why is it so, but EF automatically closed connections. Also All the patterns of repository and UnitOfWork which use EF don't use using statement. It's very strange for me, because DBContext is Disposable type, but it's a fact.

  1. The quesion is why is it so: why EF automatically releases the resource (connection) after exception? Maybe in Microsoft they did something new for handling excpetions and close connections better than in pure ADO.net?

  2. Why all the exmaples of patterns ignore using statment?

ADDED: >> For your last example, the connection is open and closed in your third line of code

Connections are created in Connection Pool just when you try to get to cxt.Items DbSet, not before and not after: enter image description here By moment of callsing Save connections already exist: enter image description here enter image description here also they existing and after leaving Save and after throwing the exception and test-method has been left: enter image description here and are closed after the program stopped working: enter image description here

Was it helpful?

Solution

DbContext does not open the connection when you initialize it. DbContext opens and closes the connection for every operation you execute eg. any query or a call to SaveChanges.

If you want to control when the connection is open or closed you will have to pass your own connection and specify that the context does not own this connection by using the overloaded constructor: public DbContext(DbConnection existingConnection, bool contextOwnsConnection)

And to answer your question, YES, you still need to use a using block or call Dispose to free any unmanaged resource. Remember that EF uses ADO.NET and this one invokes many unmanaged APIs under the hood.

hope this helps

UPDATE:
In order to verify all this create/add a new constructor for your context:

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

Then use the same code you used in your example when calling 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
}

If you use true for the second parameter in your context constructor you will notice that the connection is gone when your test finishes. This is the default behavior for a DbContext because the connection is created within and the context owns the connection (opens and closes as needed).

On the other hand if you use false you will notice the connection is still open even when the context is disposed if the connection is opened by calling conn.Open(). If the context calls conn.Open() internally to execute any query or save changes the context will control when to open and close the connection.

You can play with the second Boolean parameter and the call to conn.Open() to discover very interesting different scenarios.

The following example shows you that even when you created the connection manually, but since you didn't open it manually, the context will open and close automatically. The managed connection state is closed even before the exception is thrown and your native connection is still 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();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top