关于FirebirdClient 2.1 for .net 2.0 provider对TransactionScope的支持问题

冯嘉珍
2023-12-01

        前阵子使用FirebirdClient-2.1.0 for-net-2.0 provider 组件访问数据库,因项目中数据访问层可能是WebService,所以在业务层全部使用TransactionScope来控制事务的开启和提交。

        在FbConnection组件连接数据库时,可以在连接串中指定Enlist(True支持,False不支持)选项来启用TransactionScope的支持。

 using(TransactionScope ts = new TransactionScope())

{

         //open connection

         //update delete or insert data

         //TODO:other transaction suppert operation

         ts.Complete();

}

当我在连接串中设置Enlist选项为True后,如果不显示创建TransactionScope,对数据库操作都会引发异常。而一般写一查询数据相关的代码时习惯上都不去创建事务。如下代码会引发异常:

string connectionString = "DataSource=localhost;Database=mydb.fdb;User=SYSDBA;Password=masterkey;Enlist=True";

 using(FbConnection conn = new FbConnection(connectionString ))

{

      FbCommand cmd = new FbCommand("select * from tb_user");

      IDataReader dr = cmd.ExecuteQuery();//此处引发异常.必须先创建一个TransactionScope事务块

      //.....

}

必须要创建一个事务块:

using(TransactionScope ts = new TransactionScope())

{        

        string connectionString = "DataSource=localhost;Database=mydb.fdb;User=SYSDBA;Password=masterkey;Enlist=True";

         using(FbConnection conn = new FbConnection(connectionString ))

        {

              FbCommand cmd = new FbCommand("select * from tb_user");

              IDataReader dr = cmd.ExecuteQuery();//此处引发异常.必须先开始一个TransactionScope事务

              //.....

        }

}

解决方法:

1.修改IL代码

     当时忘了有源码直接用ildasm工具将FirebirdSql.Data.FirebirdClient.dll文件转换成il代码,找到

    .method public hidebysig instance void
          EnlistTransaction(class [System.Transactions]System.Transactions.Transaction transaction) cil managed

     在.maxstack  8下面加入

         ldnull
         ldarg.1
          call       bool [System.Transactions]System.Transactions.Transaction::op_Equality(

                     class [System.Transactions]System.Transactions.Transaction

                    ,class [System.Transactions]System.Transactions.Transaction)
          brfalse.s  IL_0000
           ret  

       再用ilasm工具编译成动态库即可。         

 2.修改Firebird Data Provider 的源代码,重新编译.

      找到FbConnectionInternal类的EnlistTransaction方法if (this.options != null && this.options.Enlist)行,修改为

if (this.options != null && this.options.Enlist && transaction != null),如下所示:

       public void EnlistTransaction(System.Transactions.Transaction transaction)
        {
            //if (this.options != null && this.options.Enlist)

            if (this.options != null && this.options.Enlist && transaction != null)//修改后
            {

                if (this.HasActiveTransaction)
                {
                    throw new ArgumentException("Unable to enlist in transaction, a local transaction already exists");
                }
                if (this.enlistmentNotification != null)
                {
                    throw new ArgumentException("Already enlisted in a transaction");
                }

                this.enlistmentNotification = new FbEnlistmentNotification(this, transaction);
                this.enlistmentNotification.Completed += new EventHandler(EnlistmentCompleted);
            }
        }

       修改完后Build项目,然后将生成的dll文件覆盖D:/Program Files/FirebirdClient 2.0/FirebirdSql.Data.FirebirdClient.dll文件,重新部署到GAC里面即可。

        修改后FbConnection组件和SqlConnection类似,如果当前上下文在隐式事务块中则自动加入到事务里,否则和普通数库操作相同。

 类似资料: