我想在提交或回滚SqlTransaction时执行一些日志记录。我看到SqlTransaction类不公开任何此类事件,如OnCommit或OnRollback。
该死! SqlTransaction类是密封的,我不能用继承来帮助它。
现在,他们不允许这些事件发生的原因是什么?
有没有办法使用SqlTransaction或提供的任何此类SqlTransaction替换来执行这些事件?
感谢。
答案 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;
}
}