Entity Framework: If you pass a connection to the context, you are responsible for disposing it
I recently got a bug report about an issue with EF Prof, apparently the application statistics would record the context being opened, but it wouldn’t show them being closed. The customer was rightfully worried about that, and wanted to know if this is a bug in his code or in EF Prof.
Not closing connections is a pretty bad idea, obviously, because you are going to hold a lot more server resources than you need.
But we couldn’t figure out what the problem was. On my end, I could see that EF Prof was recording the context close properly, but nearly the same code on the customer showed the problem. Note the word nearly. I asked for a repro of the issue, and once I had it, it took mere minutes to confirm that the problem exists.
Now was the time to find out why. The customer code was:
using(var context = new MyContext(new EntityConnection("name=MyConStr")) { // do stuff }
Now, what EF Prof tells you is a data context open & close are actually more accurately connection open & close. After some extensive study, I verified that it wasn’t my code to blame, there was a leaking connection here.
Checking a bit further, it became clear. We passed an existing connection to the context. When we dispose the context, the context asks: “Am I the owner of this connection?” And since the answer is no, it will not dispose it. It makes sense, you might want to use that connection for your own purposes, and it is pretty rude of the context to close a connection that it doesn’t own.
How can we resolve this? By giving the context the information to open the connection, but not the connection itself:
using(var context = new MyContext("name=MyConStr") { // do stuff }
This code will instruct the context to open its own connection, which it will know that it owns, so it can safely dispose it when it is disposed.
Look Ma, no leaks!
Comments
This applies to LINQ to SQL too - if the connection is a string it will open and close, if it is an existing connection it will not.
[)amien
Indeed, classes that accept parameters should not dispose of their parameters; whoever opened the connection should be responsible for closing it.
StreamReader and StreamWriter fail miserably there. Try
using (MemoryStream s = new MemoryStream) {
using (StreamWriter writer = new StreamWriter(s))
s.Seek(0);
using (StreamReader reader = new StreamReader(s))
}
Maybe i'm misunderstanding something here but how is new-ing an EntityConnection using an existing connection?
if you do:
new MyContext(new EntityConnection("name=MyConStr"))
shouldn't that create a new connection in that context?
maybe EF does this differently but i haven't worked with EF yet, so maybe i'm missing something here.
Mladen,
How is EF to know that you didn't pass it from someplace totally different?
ahhhhhh.... now i got it. If you pass any connection into it! DOH!
Comment preview