替代SqlTransaction暴露事件 - C#?

时间:2009-06-23 12:49:42

标签: c# events ado.net transactions

我想在提交或回滚SqlTransaction时执行一些日志记录。我看到SqlTransaction类不公开任何此类事件,如OnCommit或OnRollback。

该死! SqlTransaction类是密封的,我不能用继承来帮助它。

现在,他们不允许这些事件发生的原因是什么?

有没有办法使用SqlTransaction或提供的任何此类SqlTransaction替换来执行这些事件?

感谢。

3 个答案:

答案 0 :(得分:1)

一种可能性是创建一个实现IDbTransaction的类,并包装一个内部的SqlTransaction。然后你必须说:

IDbCommand icommand = (IDbCommand)command; // Where command is a SqlCommand.
command.Transaction = itransaction; // Class implementing IDbTransaction and wrapping SqlTransaction.

没有试过这个,上面的内容必须被认为是伪代码。我怀疑它甚至会起作用,但它可能值得一试。

答案 1 :(得分:0)

不。 SqlTransaction上没有内置任何内容,SqlCommand上也没有内置命令。

您可以做的最好的事情就是使用您自己的提供通知的课程。

答案 2 :(得分:0)

我们在系统中使用SqlTransaction周围的包装器。我认为这很蹩脚,但它主要起作用。请参阅下面的我们使用的完整课程。实际上它很简单。

因为我们所有的方法现在都有一个CpoTransaction类型的事务参数,所以我们还添加了一个WrapTransaction静态函数,以便在常规SqlTransaction已经启动的情况下使常规事务中的CpoTransaction失效。

请注意,在这些情况下,事务可能使用常规SqlTransaction提交/回滚,并且事件将不会触发(因此必须诉诸此类解决方案的跛足)。

/// <summary>
/// Provides a wrapper around an SqlTransaction that raises events on commit and rollback
/// </summary>
public partial class CpoTransaction : IDisposable {
    private SqlTransaction mTransaction;
    private bool mHasEnded;
    public event EventHandler Committed, RolledBack;

    /// <summary>
    /// Provides a wrapper around an SqlTransaction that raises events on commit and rollback
    /// </summary>
    /// <param name="innerTransaction">The SqlTransaction to wrap</param>
    internal CpoTransaction(SqlTransaction innerTransaction) {
        mTransaction = innerTransaction;
        mHasEnded = false;
    }
    /// <summary>
    /// Rolls back the transaction from a pending state.
    /// </summary>
    internal void RollBack() {
        if (!mHasEnded) {
            mTransaction.Rollback();
            OnRolledBack(this, new EventArgs());
            mHasEnded = true;
        } else
            throw new InvalidOperationException("Transaction has already ended.");
    }
    /// <summary>
    /// Commits the database transaction
    /// </summary>
    internal void Commit() {
        if (!mHasEnded) {
            mTransaction.Commit();
            OnCommitted(this, new EventArgs());
            mHasEnded = true;
        } else
            throw new InvalidOperationException("Transaction has already ended.");
    }
    /// <summary>
    /// Add the SqlTransaction and its associated SqlConnection to the SqlCommand
    /// </summary>
    /// <param name="command">The command to add the SqlTransaction and SqlConnection to</param>
    internal void SetTransaction(SqlCommand command) {
        if (command == null)
            throw new ArgumentNullException("command");
        command.Connection = mTransaction.Connection;
        command.Transaction = mTransaction;
    }
    /// <summary>
    /// Gets whether or not the transaction has ended
    /// </summary>
    internal bool HasEnded {
        get { return mHasEnded; }
    }
    /// <summary>
    /// Gets the internal SqlConnection
    /// </summary>
    internal SqlConnection Connection {
        get { return mTransaction.Connection; }
    }
    /// <summary>
    /// Gets the internal SqlTransaction
    /// </summary>
    public SqlTransaction InnerTransaction {
        get { return mTransaction; }
    }

    /// <summary>
    /// Wraps an existing SqlTransaction into a CpoTransaction. IMPORTANT: See remarks!
    /// </summary>
    /// <param name="transaction">The transaction to wrap</param>
    /// <returns>The SqlTransaction wrapped in a CpoTransaction</returns>
    /// <remarks>
    /// Use this method to allow CPO actions to be performed within the context of an already
    /// existing transaction.
    /// Note however that if the SqlTransaction is committed or rolled back without the use of the 
    /// CpoTransaction's Commit/Rollback functions, the events will not fire.
    /// </remarks>
    public static CpoTransaction WrapTransaction(SqlTransaction transaction) {
        return new CpoTransaction(transaction);
    }
    /// <summary>
    /// Disposes the SqlTransaction
    /// </summary>
    public void Dispose() {
        mTransaction.Dispose();
        if (!mHasEnded)
            OnRolledBack(this, new EventArgs());
        mHasEnded = true;
    }
    /// <summary>
    /// Raises the Committed event
    /// </summary>
    /// <param name="sender">The sender of the event</param>
    /// <param name="e">An EventArgs object containing event data</param>
    protected void OnCommitted(object sender, EventArgs e) {
        if (Committed != null)
            Committed(sender, e);
        Committed = null;
    }
    /// <summary>
    /// Raises the RolledBack event
    /// </summary>
    /// <param name="sender">The sender of the event</param>
    /// <param name="e">An EventArgs object containing event data</param>
    protected void OnRolledBack(object sender, EventArgs e) {
        if (RolledBack != null)
            RolledBack(sender, e);
        RolledBack = null;
    }
}