C# 一个事务中的不同数据库

C# 一个事务中的不同数据库,c#,transactions,C#,Transactions,我正在将TransactionBlock代码用于在config中存储连接字符串的web应用程序 直到现在,我只需要写一个本地数据库,因此,这段代码是有效的。但是,我现在需要另一种数据访问方法,使用不同的连接字符串写入另一个数据库 我在配置文件中创建了一个新的连接字符串,但我不确定如何调用它并将其交换掉 到目前为止,我掌握的基本代码是: public class TransactionBlock : IDisposable { private readonly bool _mFirst

我正在将
TransactionBlock
代码用于在config中存储连接字符串的web应用程序

直到现在,我只需要写一个本地数据库,因此,这段代码是有效的。但是,我现在需要另一种数据访问方法,使用不同的连接字符串写入另一个数据库

我在配置文件中创建了一个新的连接字符串,但我不确定如何调用它并将其交换掉

到目前为止,我掌握的基本代码是:

  public class TransactionBlock : IDisposable
{
    private readonly bool _mFirstTransactionBlock = false;
    private bool _mDisposed = false;

    public TransactionBlock(string connectionStringConfigKey = null)
    {
        if (connectionStringConfigKey != null && CurrentTransaction != null)
            throw new Exception("Can't create a new transactionBlock with a specific connectionstring if you are already within a block.");

        // Open a connection if we haven't yet already          
        if (CurrentTransaction == null) // we don't have a transaction yet so create one:
        {
            SqlConnection conn = new SqlConnection(ConnectionString); // Create a new connection object for the connection string.
            try
            {
                conn.Open();
            }
            catch (SqlException ex)
            {
                // Severity 20 errors are returned when there are connection
                // problems, so we only retry if the severity is 20.
                // Don't worry about deadlock errors in here - we're just connecting
                // to the database, not running anything which could be deadlocked.
                if (ex.Class != 20) throw;
                // Clear connection pool of all connections related to the given connection string.
                SqlConnection.ClearPool(conn);
                // Try to open the connection once again, catching any error.
                try { conn.Open(); }
                catch { conn = null; }
                // If 2nd attempt failed, throw original exception.
                if (conn == null) throw;
            }
            CurrentTransaction = conn.BeginTransaction();
            _mFirstTransactionBlock = true;
        }
    }

    public void Commit()
    {
        if (_mFirstTransactionBlock)
        {
            Dispose(true);
        }
    }

    public void Dispose()
    {
        if (_mFirstTransactionBlock)
        {
            Dispose(false);
        }
    }

    private void Dispose(bool commit)
    {
        if (_mDisposed)
            return; // committed and cleaned up already.

        try
        {
            var transaction = CurrentTransaction;
            var connection = transaction.Connection; // taking a reference to the connection object as rollback will set it to null;

            if (commit)
            {
                transaction.Commit();
            }
            else // rollback the transaction if it hasn't been commited.
            {
                transaction.Rollback();
            }

            if (connection != null)
            {
                connection.Close();
                connection.Dispose();
            }

            transaction.Dispose();
        }
        finally // ensure that regardless of connection exceptions, the state is set to disposed.
        {
            // remove current transaction from context.
            CurrentTransaction = null;
            _mDisposed = true;
        }
    }

    private static SqlTransaction CurrentTransaction
    {
        get
        {
            return CurrentContext.GetItem<SqlTransaction>("__Transaction");
        }
        set
        {
            CurrentContext.SetItem("__Transaction", value);
        }
    }

    public static SqlConnection Connection
    {
        get { return CurrentTransaction.Connection; }
    }
    public static SqlTransaction Transaction
    {
        get { return CurrentTransaction; }
    }

    private static string connectionString;
    public static string ConnectionString
    {
        get
        {
            if (string.IsNullOrEmpty(connectionString))
            {
                try
                {
                    connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString ?? "";
                }
                catch (Exception ex)
                {
                    ServiceLogger.LogError("Database: Creating SQL Connection. Can not find connection string. Nothing will work until this is resolved.");
                    throw;
                }
                if (string.IsNullOrEmpty(connectionString))
                    ServiceLogger.LogError("Database: Creating SQL Connection. Can not find connection string. Nothing will work until this is resolved.");
                else
                    ServiceLogger.LogInfo(String.Format("Database: Creating SQL Connection. Connection string: {0}", connectionString));
            }
            return connectionString;
        }
    }

    #region CurrentContext Helper class
    /// <summary>
    /// Helper class for easy access to the appropriate context containers.
    /// </summary>
    private static class CurrentContext
    {
        public static T GetItem<T>(string key) where T : class
        {
            if (HttpContext.Current != null)
            {
                return (T)HttpContext.Current.Items[key];
            }
            else
            {
                return (T)CallContext.GetData(key);
            }

        }
        public static void SetItem(string key, object value)
        {
            if (HttpContext.Current != null)
            {
                HttpContext.Current.Items[key] = value;
            }
            else
            {
                CallContext.SetData(key, value);
            }
        }
    }
    #endregion

    /// <summary>
    /// Adds the application name to the connection string, but only if it is missing. 
    /// </summary>
    /// <param name="connectionString"></param>
    /// <returns>Modified connection string</returns>
    private static string AddApplicationNameIfMissing(string connectionString)
    {
        if (connectionString == null)
            return null;
        // If the connection string hasn't already been configured with an application name,
        // then add one (assumes the application name is not 1st element, as unlikely to have a leading ';').
        if (connectionString.IndexOf(";Application Name=", StringComparison.OrdinalIgnoreCase) >= 0)
            return connectionString;

        // TODO: if this turns out to be too slow to perform on each query then caching connection strings should be added.
        // take site name if run from a website or webservice otherwise take process path.
        string appName = System.Web.Hosting.HostingEnvironment.SiteName ?? Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]);
        return connectionString += string.Format("{0}Application Name={1}", connectionString.EndsWith(";") ? "" : ";", appName);
    }

    private interface IStructuredParam
    {
        DataTable ToDataTable();
    }

    public SqlCommand CreateSpCommand(string sql)
    {
        if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentNullException("sql");

        SqlTransaction tran = CurrentTransaction;
        if (tran == null) throw new NullReferenceException("CurrentTransaction");

        SqlConnection conn = tran.Connection;
        if (conn == null) throw new NullReferenceException("Connection");

        SqlCommand cmd = conn.CreateCommand();
        if (cmd == null) throw new NullReferenceException("Command");

        cmd.CommandText = sql;
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Transaction = tran;
        return cmd;
    }
    public void AddParameter(SqlCommand cmd, string name, SqlDbType type, int size, object value, bool isOutput)
    {
        var p = cmd.CreateParameter();
        p.ParameterName = name;
        p.SqlDbType = type;
        p.Size = size;

        if (value == null)
            p.Value = DBNull.Value;

        else if (type == SqlDbType.Structured)
            p.Value = ((IStructuredParam)value).ToDataTable();

        else
            p.Value = value;

        p.Direction = isOutput == false ? ParameterDirection.Input : ParameterDirection.Output;
        cmd.Parameters.Add(p);
    }

    public void ExecuteAndMapReader(SqlCommand command, params Action<IDataReader>[] mappingMethods)
    {
        using (var reader = command.ExecuteReader())
        {
            int i = 0;
            do
            {
                while (reader.Read())
                {
                    if (reader.HasRows && mappingMethods != null && mappingMethods.Any())
                        mappingMethods[i](reader);
                }
                i++;
            } while (reader.NextResult());
            reader.Close();
        }
    }
}
公共类事务块:IDisposable
{
private readonly bool\u mFirstTransactionBlock=false;
private bool _mDisposed=false;
公共事务块(字符串连接StringConfigKey=null)
{
if(connectionStringConfigKey!=null&&CurrentTransaction!=null)
抛出新异常(“如果您已经在块中,则无法创建具有特定connectionstring的新transactionBlock。”);
//如果尚未打开连接,请打开连接
if(CurrentTransaction==null)//我们还没有事务,所以创建一个:
{
SqlConnection conn=newsqlconnection(ConnectionString);//为连接字符串创建一个新的连接对象。
尝试
{
conn.Open();
}
catch(SqlException-ex)
{
//存在连接时返回严重性为20的错误
//问题,因此我们仅在严重性为20时重试。
//这里不用担心死锁错误-我们只是在连接
//到数据库,不运行任何可能死锁的内容。
如果(ex.Class!=20)投掷;
//清除与给定连接字符串相关的所有连接的连接池。
SqlConnection.ClearPool(conn);
//再次尝试打开连接,捕获任何错误。
试试{conn.Open();}
捕获{conn=null;}
//如果第二次尝试失败,则引发原始异常。
如果(conn==null)抛出;
}
CurrentTransaction=conn.BeginTransaction();
_mFirstTransactionBlock=true;
}
}
公共无效提交()
{
if(mFirstTransactionBlock)
{
处置(真实);
}
}
公共空间处置()
{
if(mFirstTransactionBlock)
{
处置(虚假);
}
}
私有void Dispose(bool commit)
{
如果(_mDisposed)
return;//已提交并已清理。
尝试
{
var交易=当前交易;
var connection=transaction.connection;//将连接对象的引用作为回滚将其设置为null;
如果(提交)
{
Commit();
}
else//如果事务尚未提交,则回滚该事务。
{
transaction.Rollback();
}
if(连接!=null)
{
connection.Close();
connection.Dispose();
}
transaction.Dispose();
}
最后//确保无论连接异常如何,状态都设置为disposed。
{
//从上下文中删除当前事务。
CurrentTransaction=null;
_mDisposed=true;
}
}
私有静态SqlTransaction CurrentTransaction
{
得到
{
返回CurrentContext.GetItem(“\uu事务”);
}
设置
{
CurrentContext.SetItem(“\u事务”,值);
}
}
公共静态SqlConnection连接
{
获取{return CurrentTransaction.Connection;}
}
公共静态SqlTransaction事务
{
获取{return CurrentTransaction;}
}
私有静态字符串连接字符串;
公共静态字符串连接字符串
{
得到
{
if(string.IsNullOrEmpty(connectionString))
{
尝试
{
connectionString=ConfigurationManager.connectionString[“DefaultConnection”]。connectionString;
}
捕获(例外情况除外)
{
LogError(“数据库:正在创建SQL连接。找不到连接字符串。在解决此问题之前,任何操作都无效。”);
投掷;
}
if(string.IsNullOrEmpty(connectionString))
LogError(“数据库:正在创建SQL连接。找不到连接字符串。在解决此问题之前,任何操作都无效。”);
其他的
LogInfo(String.Format(“数据库:创建SQL连接。连接字符串:{0}”,connectionString));
}
返回连接字符串;
}
}
#区域CurrentContext助手类
/// 
///帮助器类,便于访问适当的上下文容器。
/// 
私有静态类CurrentContext
{
公共静态T GetItem(字符串键),其中T:class
{
if(HttpContext.Current!=null)
{
返回(T)HttpContext.Current.Items[key];
}
其他的
{
return(T)CallContext.GetData(key);
}
}
公共静态void SetItem(字符串键、对象值)
{
if(HttpContext.Current!=null)
{
HttpContext.Current.Items[key]=值;
}
其他的
{
SetData(键、值);
}
}
}
#端区
/// 
///将应用程序名称添加到连接字符串中,但仅当缺少该名称时。
/// 
/// 
///改良接头