简体   繁体   English

通过ADO.NET的Oracle和SQL Server上的C#事务失败

[英]C# Transactions on Oracle & SQL Server via ADO.NET failing

I have written a class in C# that is intended to offer the ability to run database transactions on a given database connection. 我在C#中编写了一个类,旨在提供在给定数据库连接上运行数据库事务的能力。 When I try to run the code however I get the following two errors on Oracle and SQL Server respectively. 当我尝试运行代码时,我分别在Oracle和SQL Server上收到以下两个错误。 Looking at my code is there an easy way around this? 看看我的代码有一个简单的方法吗?

Oracle 神谕

Connection is already part of a local or a distributed transaction 连接已经是本地或分布式事务的一部分

SQL Server 2008 SQL Server 2008

SqlConnection does not support parallel transactions SqlConnection不支持并行事务

The base class 基类

  public abstract class DbFactoryDatabaseTransaction
  {
    public void DoTransaction(IDatabaseConnectivityObjectBasicResponse databaseConnectivityObject)
    {
        databaseConnectivityObject.PrepareConnection();

        DbTransaction dbTransaction = databaseConnectivityObject.DBFactoryDatabaseConnection.BeginTransaction();

        try
        {
            ExecuteSql(databaseConnectivityObject, dbTransaction);

            dbTransaction.Commit();
        }
        catch (Exception ex)
        {
            dbTransaction.Rollback();

            databaseConnectivityObject.Close();

            throw;
        }
        finally
        {
            dbTransaction.Dispose();
        }
    }


    /// <summary>
    /// A method to allow the caller to decide how the SQL statements are called as part of a transaction
    /// </summary>
    public abstract void ExecuteSql(IDatabaseConnectivityObjectBasicResponse databaseConnectivityObject, DbTransaction dbTransaction);
}

The override method 覆盖方法

public override void ExecuteSql(IDatabaseConnectivityObjectBasicResponse databaseConnectivityObject, DbTransaction dbTransaction)
    {
        //oracle
        List<string> transactions = new List<string>
            {
                "INSERT INTO TMA_NOT_TO_ENTITY_QUEUE (RECEIVED_NOTICE_ID, NOTICE_TEXT, STATE_ID, TIME_RECEIVED) VALUES (1, 'This is a notice', 1, to_date('2012/08/15', 'yyyy/mm/dd'))",
                "INSERT INTO TMA_NOT_TO_ENTITY_QUEUE (RECEIVED_NOTICE_ID, NOTICE_TEXT, STATE_ID, TIME_RECEIVED) VALUES (2, 'This is a notice', 1, to_date('2012/08/15', 'yyyy/mm/dd'))",
                "INSERT INTO TMA_NOT_TO_ENTITY_QUEUE (RECEIVED_NOTICE_ID, NOTICE_TEXT, STATE_ID, TIME_RECEIVED) VALUES (3, 'This is a notice', 1, to_date('2012/08/15', 'yyyy/mm/dd'))",
                "INSERT INTO TMA_NOT_TO_ENTITY_QUEUE (RECEIVED_NOTICE_ID, NOTICE_TEXT, STATE_ID, TIME_RECEIVED) VALUES (4, 'This is a notice', 1, to_date('2012/08/15', 'yyyy/mm/dd'))",
                "INSERT INTO TMA_NOT_TO_ENTITY_QUEUE (RECEIVED_NOTICE_ID, NOTICE_TEXT, STATE_ID, TIME_RECEIVED) VALUES (5, 'This is a notice', 1, to_date('2012/08/15', 'yyyy/mm/dd'))",
                "INSERT INTO TMA_NOT_TO_ENTITY_QUEUE (RECEIVED_NOTICE_ID, NOTICE_TEXT, STATE_ID, TIME_RECEIVED) VALUES (6, 'This is a notice', 1, to_date('2012/08/15', 'yyyy/mm/dd'))"
            };

        databaseConnectivityObject.DBFactoryDatabaseCommand.Transaction = databaseConnectivityObject.DBFactoryDatabaseConnection.BeginTransaction();

        foreach (var transaction in transactions)
        {
            databaseConnectivityObject.DBFactoryDatabaseCommand.CommandText = transaction;
            databaseConnectivityObject.DBFactoryDatabaseCommand.CommandType = CommandType.Text;
            databaseConnectivityObject.DBFactoryDatabaseCommand.Transaction = dbTransaction;
            databaseConnectivityObject.DBFactoryDatabaseCommand.ExecuteNonQuery();
        }
    }

The calling method 调用方法

    public void RunTransaction()
        {
        IDatabaseConnectivityObjectBasicResponse databaseConnectivityObject = new DbProviderFactoryConnectionBasic();

        DoTransaction(databaseConnectivityObject);
        }

The test method 测试方法

    [TestMethod()]
    public void RunTransactionTest()
    {
        TmaNoticeToClusteredEntityValidation target = new TmaNoticeToClusteredEntityValidation(BindVariables, SqlFactory, Dialect); 
        target.RunTransaction();
        Assert.Inconclusive("A method that does not return a value cannot be verified.");
    }

It turns out that the problem was actually that I was calling BeginTransaction twice() on the connection object. 事实证明问题实际上是我在连接对象上调用了BeginTransaction两次()。 This was solved by removing databaseConnectivityObject.DBFactoryDatabaseCommand.Transaction = databaseConnectivityObject.DBFactoryDatabaseConnection.BeginTransaction(); 这是通过删除databaseConnectivityObject.DBFactoryDatabaseCommand.Transaction = databaseConnectivityObject.DBFactoryDatabaseConnection.BeginTransaction();来解决的databaseConnectivityObject.DBFactoryDatabaseCommand.Transaction = databaseConnectivityObject.DBFactoryDatabaseConnection.BeginTransaction(); from the override method. 来自覆盖方法。

Just omit this line on override 在覆盖时省略这一行

databaseConnectivityObject.DBFactoryDatabaseCommand.Transaction = databaseConnectivityObject.DBFactoryDatabaseConnection.BeginTransaction();

And change this 并改变这一点

databaseConnectivityObject.DBFactoryDatabaseCommand.Transaction = dbTransaction;

To

databaseConnectivityObject.DBFactoryDatabaseCommand.Connection= databaseConnectivityObject.DBFactoryDatabaseConnection;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM