我正在尝试使用一些环境事务范围(谢谢,entity-framework ),我之前没有真正做过,而且我看到了一些......奇怪的我想要了解的行为。
我正在尝试登记当前的事务范围,并在成功完成后做一些工作。我的征募参与者由于拥有一些资源而实施IDisposable
。我有一个展示奇怪行为的简单例子。
对于这门课程,
class WtfTransactionScope : IDisposable, IEnlistmentNotification
{
public WtfTransactionScope()
{
if(Transaction.Current == null)
return;
Transaction.Current.EnlistVolatile(this, EnlistmentOptions.None);
}
void IEnlistmentNotification.Commit(Enlistment enlistment)
{
enlistment.Done();
Console.WriteLine("Committed");
}
void IEnlistmentNotification.InDoubt(Enlistment enlistment)
{
enlistment.Done();
Console.WriteLine("InDoubt");
}
void IEnlistmentNotification.Prepare(
PreparingEnlistment preparingEnlistment)
{
Console.WriteLine("Prepare called");
preparingEnlistment.Prepared();
Console.WriteLine("Prepare completed");
}
void IEnlistmentNotification.Rollback(Enlistment enlistment)
{
enlistment.Done();
Console.WriteLine("Rolled back");
}
public void Dispose()
{
Console.WriteLine("Disposed");
}
}
如图所示使用
using(var scope = new TransactionScope())
using(new WtfTransactionScope())
{
scope.Complete();
}
控制台输出演示了wtf-ness:
处理完毕
准备叫做 承诺
准备完成
我在交易完成之前就已经处理好了。这种......否定了挂起交易范围的好处。我希望一旦交易成功(或不成功),我就会得到通知,这样我就可以做一些工作了。我很遗憾 假设这会在scope.Complete()
之后以及在我们离开using
范围之前被处理掉之前发生。显然事实并非如此。
当然,我可以破解它。但我有其他问题基本上阻止我这样做。在这种情况下,我将不得不废弃并做其他事情。
我在这里做错了吗?或者这是预期的行为?可以采取不同的措施来防止这种情况发生吗?
答案 0 :(得分:14)
这是自己造成的痛苦。您违反了IDisposable的一个非常基本的规则,只有在其他任何地方不再使用时,才应该处置该对象。当您的using语句调用Dispose()时, 正在使用,您在WtfTransactionScope构造函数中提交了对象的引用。在完成它之前你不能处置它,这必然意味着你必须在之后处理它,因为TransactionScope的using语句完成并且事务已经提交/回滚。
我会让你烦恼使它漂亮,但一个显而易见的方法是:
using(var wtf = new WtfTransactionScope())
using(var scope = new TransactionScope())
{
wtf.Initialize();
scope.Complete();
}
Prepare completed
只是一个无用的调试语句。只需将其删除即可。