// Copyright (c) 2006, Microsoft Corporation
//
// Author: Alazel Acheson
// History:
// 3/13/2006 - Added DbConnectionScopeOption support and TryGetConnection.
namespace Microsoft.Samples.DbConnectionScope {
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
///
/// Options for modifying how DbConnectionScope.Current is affected while constructing a new scope.
///
public enum DbConnectionScopeOption {
Required, // Set self as currentScope if there isn't one already on the thread, otherwise don't do anything.
RequiresNew, // Push self as currentScope (track prior scope and restore it on dispose).
Suppress, // Push null reference as currentScope (track prior scope and restore it on dispose).
}
// Allows almost-automated re-use of connections across multiple call levels
// while still controlling connection lifetimes. Multiple connections are supported within a single scope.
// To use:
// Create a new connection scope object in a using statement at the level within which you
// want to scope connections.
// Use Current.AddConnection() and Current.GetConnection() to store/retrieve specific connections based on your
// own keys.
// Simpler alternative: Use Current.GetOpenConnection(factory, connection string) where you need to use the connection
//
// Example of simple case:
// void TopLevel() {
// using (DbConnectionScope scope = new DbConnectionScope()) {
// // Code that eventually calls LowerLevel a couple of times.
// // The first time LowerLevel is called, it will allocate and open the connection
// // Subsequent calls will use the already-opened connection, INCLUDING running in the same
// // System.Transactions transaction without using DTC (assuming only one connection string)!
// }
// }
//
// void LowerLevel() {
// string connectionString = <...get connection string from config or somewhere...>;
// SqlCommand cmd = new SqlCommand("Some TSQL code");
// cmd.Connection = (SqlConnection) DbConnectionScope.Current.GetOpenConnection(SqlClientFactory.Instance, connectionString);
// ... finish setting up command and execute it
// }
///
/// Class to assist in managing connection lifetimes inside scopes on a particular thread.
///
sealed public class DbConnectionScope : IDisposable
{
#region class fields
[ThreadStatic()]
private static DbConnectionScope __currentScope = null; // Scope that is currently active on this thread
private static Object __nullKey = new Object(); // used to allow null as a key
#endregion
#region instance fields
private DbConnectionScope _priorScope; // previous scope in stack of scopes on this thread
private Dictionary