Add the ability to track Open Transactions via IDalSession
----------------------------------------------------------

                 Key: IBATISNET-212
                 URL: https://issues.apache.org/jira/browse/IBATISNET-212
             Project: iBatis for .NET
          Issue Type: Improvement
          Components: DataMapper
         Environment: Any
            Reporter: Samuel Clough


At times, a method call may need to call another method call as part of one 
logical data insert/update operation.  Currently the problem is that iBatis 
does not expose in the session interface whether or not their is an open 
transaction.  Because of this, a method that may be called as part of a larger 
data update has no way of checking to see if a transaction is open before 
opening another one.  Some RDMSs allow nested transactions and this is not a 
problem, but other providers do not and it can become a problem.  The 
suggestion is that iBatis expose the _isOpenTransaction field on the session 
via a property so that it can be checked in a method call when a method needs 
to determine if it should open a transaction or not.  

Below is a sample use case where ObjectB can be updated, but ObjectB is also a 
property of ObjectA and when ObjectA is updated, the embedded ObjectB should be 
updated as well all within one transaction.  (This is just an example, not 
great code).

class Example
{
    private ISqlMapper _mapper = null;
    
    public Example()
    {
        _mapper = Mapper.Instance();
    }
    public void UpdateA(ObjectA a)
    {
        _dataMapper.StartTransaction();
        _dataMapper.update("update-a", a);
        UpdateB(a.ObjectB);
        _dataMapper.CommitTransaction();
    }
    public void UpdateB(ObjectB b)
    {
        bool existingTransaction = _dataMapper.TransactionOpen;
        if (!existingTransaction)
        {
            _dataMapper.StartTransaction();
        }
        _dataMapper.Update("update-b", b);
        if (!existingTransaction)
        {
            _dataMapper.CommitTransaction();
        }
    }
}


This has been a major need for us on some projects and I would suppose for 
others as well.  For that reason, we are proposing this enhancement rather than 
creating some in house solution or a custom iBatis build.  In order to make the 
changes, the following changes would need to be made to the code:

The IBatisNet.Common.IDalSession interface would need the following new 
property:

bool OpenTransaction{ get; }

The IBatisNet.DataMapper.SqlMapSession would need the following changes:

1.  Implement the new property to expose the existing field.:
public bool OpenTransaction
{
     get { return _isOpenTransaction; }
}

2. Update the CommitTransaction methods to be as follows including an update to 
the _isOpenTransaction field:
                /// <summary>
                /// Commits the database transaction.
                /// </summary>
                /// <remarks>
                /// Will close the connection.
                /// </remarks>
                public void CommitTransaction()
                {
                        if (_logger.IsDebugEnabled)
                        {
                                _logger.Debug("Commit Transaction.");
                        }
                        _transaction.Commit();
                        _transaction.Dispose();
                       _isOpenTransaction = false;
                        if (_connection.State != ConnectionState.Closed)
                        {
                                this.CloseConnection();
                        }
                }

                /// <summary>
                /// Commits the database transaction.
                /// </summary>
                /// <param name="closeConnection">Close the connection</param>
                public void CommitTransaction(bool closeConnection)
                {
                        if (closeConnection)
                        {
                                this.CommitTransaction();
                        }
                        else
                        {
                                _transaction.Commit();
                                if (_logger.IsDebugEnabled)
                                {
                                        _logger.Debug("Commit Transaction.");
                                }
                                _transaction.Dispose();
                               _isOpenTransaction = false;
                        }
                }

3.  Update the RollbackTransaction methods to set the state of the 
_isOpenTransaction field as follows:
                /// <summary>
                /// Rolls back a transaction from a pending state.
                /// </summary>
                /// <remarks>
                /// Will close the connection.
                /// </remarks>
                public void RollBackTransaction()
                {
                        _transaction.Rollback();
                        if (_logger.IsDebugEnabled)
                        {
                                _logger.Debug("RollBack Transaction.");
                        }
                        _transaction.Dispose();
                        _transaction = null;
                       _isOpenTransaction = false;
                        if (_connection.State != ConnectionState.Closed)
                        {
                                this.CloseConnection();
                        }
                }

                /// <summary>
                /// Rolls back a transaction from a pending state.
                /// </summary>
                /// <param name="closeConnection">Close the connection</param>
                public void RollBackTransaction(bool closeConnection)
                {
                        if (closeConnection)
                        {
                                this.RollBackTransaction();
                        }
                        else
                        {
                                if (_logger.IsDebugEnabled)
                                {
                                        _logger.Debug("RollBack Transaction.");
                                }
                                _transaction.Rollback();
                                _transaction.Dispose();
                                _transaction = null;
                                _isOpenTransaction = false;
                        }
                }

This would be very helpful when developing against RDMS servers and/or 
providers that do not support nested transactions as well as be more efficient 
than nested transactions.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to