一个事务中的不同数据库

时间:2016-01-27 13:37:20

标签: c# transactions

我正在将TransactionBlock代码用于在连接字符串中存储连接字符串的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();
        }
    }
}

0 个答案:

没有答案