从Excel VBA开始一个TransactionScope?

7
我有一些现有的C#代码,希望通过COM互操作公开,以便可以从Excel VBA调用。由于我将执行许多嵌套的批量更新操作,因此需要支持事务,并且为了最小化在C#级别上所需的重构,我想使用TransactionScope方法:
使用Transaction Scope实现隐式事务 http://msdn.microsoft.com/en-us/library/ms172152.aspx
TransactionScope类提供了一种简单的方式来标记一个代码块参与事务,而不需要你与事务本身进行交互。事务范围可以自动选择和管理环境事务。由于其易用性和效率,建议在开发事务应用程序时使用TransactionScope类。
此外,您无需显式地使用事务注册资源。任何System.Transactions资源管理器(如SQL Server 2005)都可以检测到由作用域创建的环境事务的存在并自动注册。
我的问题是:在VBA代码中是否可以启动TransactionScope(或通过COM互操作调用c#方法来实例化和返回TransactionScope对象),然后继续通过COM互操作调用各种其他c#对象,这些对象都将自动参与单个根事务?

不,你绝对不能在VBA中这样做。 - user2140173
你能详细说明一下吗?(希望我没有让你证明一个否定的东西) - tbone
我已经删除了我的回答,因为我认为我们对于C#中的TransactionScope以及在VBA中的作用并不在同一个理解层面上。ADODB实现了在事务期间回滚任何更改的机制,但是你不能将任何VBA代码块包装在TransactionScope中,并在事务失败时将其回滚... - user2140173
1个回答

1
我觉得你的方法没有问题。在VBA中没有using,所以你需要通过以下方式模拟:
  • 使用错误处理程序并
  • 非常小心地不要在某种情况下离开方法而不处置TransactionScope。
例如,在你的C#应用程序中,你提供了以下方法:
public TransactionScope BeginTransactionScope()
{
    return new TransactionScope();
}

public void CommitTransactionScope(TransactionScope scope)
{
    scope.Complete();
    scope.Dispose();  // simulates leaving the using { ... } scope
}

public void RollbackTransactionScope(TransactionScope scope)
{
    scope.Dispose();  // simulates leaving the using { ... } scope
}

// Does some work using Connections and maybe nested scopes
public void DoSomeWork1() { ... }
public void DoSomeWork2() { ... }
public void DoSomeWork3() { ... }

你需要通过COM互操作将编译好的C# DLL提供给Excel VBA。在VBA中,你可以按照以下方式运行方法:
Private Sub MySub()

    On Error Goto MyErrorHandler

    ...
    Dim scope As Object
    Set scope = myCsObject.BeginTransactionScope()
    ...
    myCsObject.DoSomeWork1
    ...
    myCsObject.DoSomeWork2
    ...
    myCsObject.DoSomeWork3
    ...
    myCsObject.CommitTransactionScope scope
    Set scope = Nothing
    ...

    Exit Sub

MyErrorHandler:
    If Not (scope Is Nothing) Then
        myCsObject.RollbackTransactionScope scope
    End If
    ' Remainder of your error handler goes here
    ...
End Sub

请注意,使用VBA代码(在DoSomeWork调用之间)执行的任何数据访问都将位于事务范围之外,因为TransactionScope与经典的ADO或DAO不兼容。

@mehow:1. 感谢您发现了这个错别字,已经修复。2. 也许他需要在各种“DoSomeWork”调用之间执行VBA代码?无论如何,这是一个好问题,但它可能更适合问原帖作者而不是我。 - Heinzi
@mehow:确实,usingWith在某种程度上都创建了作用域,但是using在其作用域结束时调用Dispose,而With仅提供了访问字段和方法的词法快捷方式。 - Heinzi
是的,但您可以创建一个实现IDispose接口的自定义类,当所有对象的引用都被释放时,它最终会被调用(VBA使用引用计数)。而您也可以为原始的TransactionScope创建一个自己的TransactionScopeWrapper类包装器的实例,但不幸的是,System.TransactionScope不可见于COM。 - user2140173
@mehow:TransactionScope不可见可能确实是一个问题,尽管需要测试才能确定。毕竟,在VBA中我们没有调用它的任何方法,只是保留引用。如果这是个问题,我同意COM可见的包装对象可能是最简单的解决方案(例如,在给定示例中,只需将对scope的引用保留在myCsObject的私有字段中)。 - Heinzi
这正是我所想的。@mehow,你认为这会起作用吗(与首先采取这种方式是否明智无关!) - tbone
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接