当前位置:  开发笔记 > 编程语言 > 正文

我可以从SqlConnection对象获取对待处理事务的引用吗?

如何解决《我可以从SqlConnection对象获取对待处理事务的引用吗?》经验,为你挑选了2个好方法。

假设某人(除了我)编写以下代码并将其编译为程序集:

using (SqlConnection conn = new SqlConnection(connString)) 
{
    conn.Open();
    using (var transaction = conn.BeginTransaction())
    {
        /* Update something in the database */
        /* Then call any registered OnUpdate handlers */
        InvokeOnUpdate(conn);

        transaction.Commit();
    }
}

对InvokeOnUpdate(IDbConnection conn)的调用调用了一个我可以实现并注册的事件处理程序.因此,在这个处理程序中,我将引用IDbConnection对象,但我不会引用挂起的事务.我有什么办法可以控制交易吗?在我的OnUpdate处理程序中,我想执行类似于以下内容的操作:

private void MyOnUpdateHandler(IDbConnection conn) 
{
    var cmd = conn.CreateCommand();
    cmd.CommandText = someSQLString;
    cmd.CommandType = CommandType.Text;

    cmd.ExecuteNonQuery();
}

但是,对cmd.ExecuteNonQuery()的调用会抛出InvalidOperationException,抱怨它

"当分配给命令的连接处于挂起的本地事务中时,ExecuteNonQuery要求命令具有事务.该命令的Transaction属性尚未初始化".

我可以以任何方式使用挂起的事务登记我的SqlCommand cmd吗?我可以从IDbConnection对象中检索对待处理事务的引用(如果需要,我很乐意使用反射)?



1> Alvaro Rodri..:

如果有人对反射代码感兴趣来完成这个,那么它在这里:

    private static readonly PropertyInfo ConnectionInfo = typeof(SqlConnection).GetProperty("InnerConnection", BindingFlags.NonPublic | BindingFlags.Instance);
    private static SqlTransaction GetTransaction(IDbConnection conn) {
        var internalConn = ConnectionInfo.GetValue(conn, null);
        var currentTransactionProperty = internalConn.GetType().GetProperty("CurrentTransaction", BindingFlags.NonPublic | BindingFlags.Instance);
        var currentTransaction = currentTransactionProperty.GetValue(internalConn, null);
        var realTransactionProperty = currentTransaction.GetType().GetProperty("Parent", BindingFlags.NonPublic | BindingFlags.Instance);
        var realTransaction = realTransactionProperty.GetValue(currentTransaction, null);
        return (SqlTransaction) realTransaction;
    }

笔记:

类型是内部的,属性是私有的,因此您不能使用动态

内部类型也会阻止您像第一个ConnectionInfo那样声明中间类型.必须在对象上使用GetType


在继续之前检查currentTransaction可能是个好主意.if(currentTransaction == null)返回null;

2> JoshBerke..:

哇我一开始并不相信.我很惊讶CreateCommand()在使用本地SQL Server事务时没有给它命令它的事务,并且事务没有在SqlConnection对象上公开.实际上,当反映SqlConnection当前事务时甚至不存储在该对象中.在下面的编辑中,我给了你一些提示,通过他们的一些内部类来追踪对象.

我知道你不能修改方法但是你可以在方法栏周围使用TransactionScope吗?所以如果你有:

public static void CallingFooBar()
{
   using (var ts=new TransactionScope())
   {
      var foo=new Foo();
      foo.Bar();
      ts.Complete();
   }
}

这将有效,我使用类似的代码测试你的,一旦我添加包装所有工作正常,如果你可以这样做当然.正如所指出的那样,如果在TransactionScope您内部打开了多个连接,您将被升级为分布式事务,除非为您配置系统,否则您将收到错误消息.

加入DTC也比本地交易慢几倍.

编辑

如果你真的想尝试使用反射,SqlConnection有一个SqlInternalConnection,它依次有一个AvailableInternalTransaction属性,它返回一个SqlInternalTransaction,它有一个Parent属性,它返回你需要的SqlTransaction.

推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有