Thursday, August 30, 2007

Don't forget to close your Linq to Sql connections

Today I was working on some Linq to Sql code that dealt with an event management system. There are events people can attend, and attendees fill out a form to register for the event. The fields for each event are configurable by the person that creates the event. When I save a set of event fields I want to do it in a transaction so I don't end up with a partial "record". Here's what my code looked like originally:

public void SaveEventAttendeeFields(EventAttendeeField[] fields)
{
using (LinqToSqlDataContext dc = new LinqToSqlDataContext())
{
dc.DeferredLoadingEnabled = false;

try { dc.Connection.Open(); dc.Transaction = dc.Connection.BeginTransaction(); foreach (EventAttendeeField f in fields)
{
if (f.EventAddendeeFieldId > 0)
dc.EventAttendeeFields.Attach(f, true);
else dc.EventAttendeeFields.Add(f); } dc.SubmitChanges(); dc.Transaction.Commit(); } catch { if (null != dc.Transaction)
dc.Transaction.Rollback();

throw;
}
}
}

I assumed this was perfectly fine, until I ran it through my unit test library. My test library automatically creates a new database, tables, sprocs, and then populates it with seed test data. At the end of the test run it drops the database that was created. Well, the drop was failing because the database was in use! I thought "hmm, I wonder if my connections aren't being closed." Sure enough, if you manually open the connection in the DataContext you had better manually close it as well!

public void SaveEventAttendeeFields(EventAttendeeField[] fields)
{
using (LinqToSqlDataContext dc = new LinqToSqlDataContext())
{
dc.DeferredLoadingEnabled = false;

try { dc.Connection.Open(); dc.Transaction = dc.Connection.BeginTransaction(); foreach (EventAttendeeField f in fields)
{
if (f.EventAddendeeFieldId > 0)
dc.EventAttendeeFields.Attach(f, true);
else dc.EventAttendeeFields.Add(f); } dc.SubmitChanges(); dc.Transaction.Commit(); } finally { if (null != dc.Connection && dc.Connection.State != System.Data.ConnectionState.Closed)
dc.Connection.Close();
}
}
}

This code didn't cause any leaks. So, moral of the story, close your connections in your DataContext if you open them.

No comments:

Post a Comment

About the Author

Wow, you made it to the bottom! That means we're destined to be life long friends. Follow Me on Twitter.

I am an entrepreneur and hacker. I'm a Cofounder at RealCrowd. Most recently I was CTO at Hive7, a social gaming startup that sold to Playdom and then Disney. These are my stories.

You can find far too much information about me on linkedin: http://linkedin.com/in/jdconley. No, I'm not interested in an amazing Paradox DBA role in the Antarctic with an excellent culture!