/// <summary>
        /// Begin a new transaction with the given transaction definition.
        /// </summary>
        /// <param name="transaction">
        /// Transaction object returned by
        /// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.
        /// </param>
        /// <param name="definition">
        /// <see cref="Spring.Transaction.ITransactionDefinition"/> instance, describing
        /// propagation behavior, isolation level, timeout etc.
        /// </param>
        /// <remarks>
        /// Does not have to care about applying the propagation behavior,
        /// as this has already been handled by this abstract manager.
        /// </remarks>
        /// <exception cref="Spring.Transaction.TransactionException">
        /// In the case of creation or system errors.
        /// </exception>
        protected override void DoBegin(object transaction, ITransactionDefinition definition)
        {
            DbProviderTransactionObject txMgrStateObject =
                (DbProviderTransactionObject)transaction;
            IDbConnection con = null;

            if (dbProvider == null)
            {
                throw new ArgumentException("DbProvider is required to be set on AdoPlatformTransactionManager");
            }

            try
            {
                if (txMgrStateObject.ConnectionHolder == null || txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction)
                {
                    IDbConnection newCon = DbProvider.CreateConnection();
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Acquired Connection [" + newCon + ", " + newCon.ConnectionString + "] for ADO.NET transaction");
                    }
                    newCon.Open();

                    //TODO isolation level mgmt - will need to abstract out SQL used to specify this in DbMetaData
                    //MSDN docs...
                    //With one exception, you can switch from one isolation level to another at any time during a transaction. The exception occurs when changing from any isolation level to SNAPSHOT isolation


                    //IsolationLevel previousIsolationLevel =

                    IDbTransaction newTrans = newCon.BeginTransaction(definition.TransactionIsolationLevel);

                    txMgrStateObject.SetConnectionHolder(new ConnectionHolder(newCon, newTrans), true);
                }
                txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction = true;
                con = txMgrStateObject.ConnectionHolder.Connection;


                txMgrStateObject.ConnectionHolder.TransactionActive = true;

                int timeout = DetermineTimeout(definition);
                if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
                {
                    txMgrStateObject.ConnectionHolder.TimeoutInSeconds = timeout;
                }


                //Bind transactional resources to thread
                if (txMgrStateObject.NewConnectionHolder)
                {
                    TransactionSynchronizationManager.BindResource(DbProvider,
                                                                   txMgrStateObject.ConnectionHolder);
                }
            }
            //TODO catch specific exception
            catch (Exception e)
            {
                ConnectionUtils.DisposeConnection(con, DbProvider);
                throw new CannotCreateTransactionException("Could not create ADO.NET connection for transaction", e);
            }
        }
        /// <summary>
        /// Suspend the resources of the current transaction.
        /// </summary>
        /// <param name="transaction">Transaction object returned by
        /// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param>
        /// <returns>
        /// An object that holds suspended resources (will be kept unexamined for passing it into
        /// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoResume"/>.)
        /// </returns>
        /// <remarks>
        /// Transaction synchronization will already have been suspended.
        /// </remarks>
        /// <exception cref="Spring.Transaction.IllegalTransactionStateException">
        /// If suspending is not supported by the transaction manager implementation.
        /// </exception>
        /// <exception cref="Spring.Transaction.TransactionException">
        /// in case of system errors.
        /// </exception>
        protected override object DoSuspend(object transaction)
        {
            DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)transaction;

            txMgrStateObject.ConnectionHolder = null;
            ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.UnbindResource(DbProvider);

            return(conHolder);
        }
        /// <summary>
        /// Check if the given transaction object indicates an existing,
        /// i.e. already begun, transaction.
        /// </summary>
        /// <param name="transaction">
        /// Transaction object returned by
        /// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.
        /// </param>
        /// <returns>True if there is an existing transaction.</returns>
        /// <exception cref="Spring.Transaction.TransactionException">
        /// In the case of system errors.
        /// </exception>
        protected override bool IsExistingTransaction(object transaction)
        {
            DbProviderTransactionObject txMgrStateObject =
                (DbProviderTransactionObject)transaction;

            return(txMgrStateObject.ConnectionHolder != null
                   &&
                   txMgrStateObject.ConnectionHolder.TransactionActive);
        }
 /// <summary>
 /// Return the current transaction object.
 /// </summary>
 /// <returns>The current transaction object.</returns>
 /// <exception cref="Spring.Transaction.CannotCreateTransactionException">
 /// If transaction support is not available.
 /// </exception>
 /// <exception cref="Spring.Transaction.TransactionException">
 /// In the case of lookup or system errors.
 /// </exception>
 protected override object DoGetTransaction()
 {
     DbProviderTransactionObject txMgrStateObject =
         new DbProviderTransactionObject();
     txMgrStateObject.SavepointAllowed = NestedTransactionsAllowed;
     ConnectionHolder conHolder = 
         (ConnectionHolder) TransactionSynchronizationManager.GetResource(DbProvider);
     txMgrStateObject.SetConnectionHolder(conHolder, false);
     return txMgrStateObject;
 }
        /// <summary>
        /// Return the current transaction object.
        /// </summary>
        /// <returns>The current transaction object.</returns>
        /// <exception cref="Spring.Transaction.CannotCreateTransactionException">
        /// If transaction support is not available.
        /// </exception>
        /// <exception cref="Spring.Transaction.TransactionException">
        /// In the case of lookup or system errors.
        /// </exception>
        protected override object DoGetTransaction()
        {
            DbProviderTransactionObject txMgrStateObject =
                new DbProviderTransactionObject();

            txMgrStateObject.SavepointAllowed = NestedTransactionsAllowed;
            ConnectionHolder conHolder =
                (ConnectionHolder)TransactionSynchronizationManager.GetResource(DbProvider);

            txMgrStateObject.SetConnectionHolder(conHolder, false);
            return(txMgrStateObject);
        }
        /// <summary>
        /// Set the given transaction rollback-only. Only called on rollback
        /// if the current transaction takes part in an existing one.
        /// </summary>
        /// <param name="status">The status representation of the transaction.</param>
        /// <exception cref="Spring.Transaction.TransactionException">
        /// In the case of system errors.
        /// </exception>
        protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
        {
            DbProviderTransactionObject txMgrStateObject =
                (DbProviderTransactionObject)status.Transaction;

            if (status.Debug)
            {
                IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection;
                log.Debug("Setting ADO.NET transaction [" + conn + ", " + conn.ConnectionString + "] rollback-only.");
            }
            txMgrStateObject.SetRollbackOnly();
        }
        /// <summary>
        /// Perform an actual rollback on the given transaction.
        /// </summary>
        /// <param name="status">The status representation of the transaction.</param>
        /// <remarks>
        /// An implementation does not need to check the new transaction flag.
        /// </remarks>
        /// <exception cref="Spring.Transaction.TransactionException">
        /// In the case of system errors.
        /// </exception>
        protected override void DoRollback(DefaultTransactionStatus status)
        {
            DbProviderTransactionObject txMgrStateObject =
                (DbProviderTransactionObject)status.Transaction;
            IDbConnection  conn  = txMgrStateObject.ConnectionHolder.Connection;
            IDbTransaction trans = txMgrStateObject.ConnectionHolder.Transaction;

            if (status.Debug)
            {
                log.Debug("Rolling back ADO.NET transaction on Connection [" + conn + ", " + conn.ConnectionString + "]");
            }
            try
            {
                trans.Rollback();
            }
            catch (Exception e)
            {
                throw new TransactionSystemException("Could not rollback ADO.NET transaction", e);
            }
        }
        protected override void DoCleanupAfterCompletion(object transaction)
        {
            DbProviderTransactionObject txMgrStateObject =
                (DbProviderTransactionObject)transaction;

            if (txMgrStateObject.NewConnectionHolder)
            {
                TransactionSynchronizationManager.UnbindResource(DbProvider);
            }
            IDbConnection con = txMgrStateObject.ConnectionHolder.Connection;

            if (log.IsDebugEnabled)
            {
                log.Debug("Releasing ADO.NET Connection [" + con + ", " + con.ConnectionString + "] after transaction");
            }

            ConnectionUtils.DisposeConnection(con, DbProvider);
            //TODO clear out IDbTransaction object?

            txMgrStateObject.ConnectionHolder.Clear();
        }