Uploaded image for project: 'iBatis for .NET'
  1. iBatis for .NET
  2. IBATISNET-212

Add the ability to track Open Transactions via IDalSession

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Closed
    • Major
    • Resolution: Fixed
    • None
    • DataMapper 1.6.1
    • DataMapper
    • None
    • Any

    Description

      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.

      Attachments

        1. SqlMapSession.cs
          14 kB
          Samuel Clough
        2. IDalSession.cs
          6 kB
          Samuel Clough

        Activity

          People

            gilles Gilles Bayon
            sclough Samuel Clough
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: