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.