I’ve heard a few comments from people who would like an easier way to manage connection lifetime & use across multiple methods. Most often, the problem is due to using a TransactionScope at an higher level, but opening and closing connections inside the methods – generally resulting in a distributed transaction unless you manually move a single connection around. For example:
void OuterMethod() { using (TransactionScope tx = new TransactionScope(TransactionScopeOption.RequiresNew, opts)) { InnerMethod("select * from testtable"); InnerMethod("update testtable set col1 = N'new value'"); tx.Complete(); }}
static void InnerMethod(string sqlText) { using (SqlConnection conn = SqlConnection(connStr)) { conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.ExecuteNonQuery(); }}
To avoid the distributed transaction, you would need to create the connection in the OuterMethod and pass it in as a parameter (somewhat tedious) or assign it to a member variable (somewhat risky, as you are then probably maintaining a reference to the connection beyond it’s intended lifetime).
I've implemented a simple scope class for db connections that can simplify the process (see the attached file). Feel free to use this class directly or modify it as needed.
To use it, simply create a new DbConnectionScope in the OuterMethod and follow one of the two patterns for getting your connection to the inner scope:
The example, re-written using the second pattern, looks like this:
void OuterMethod() {
using (TransactionScope tx = new TransactionScope(TransactionScopeOption.RequiresNew, opts)) {
using (DbConnectionScope db = new DbConnectionScope()) {
InnerMethod("select * from testtable");
InnerMethod("update testtable set col1 = N'new value'");
tx.Complete();
}
static void InnerMethod(string sqlText) {
SqlCommand cmd = new SqlCommand();
cmd.Connection = (SqlConnection) DbConnectionScope.Current.GetOpenConnection(SqlClientFactory.Instance, connStr);
cmd.ExecuteNonQuery();
Disclaimer: This posting is provided "AS IS" with no warranties, and confers no rights
Updated: Fixed a glaringly simple bug in the Dispose() method.
Updated: Missed one other bug, now fixed.