Как заставить библиотеку экстентов использовать транзакцию SQL - PullRequest
0 голосов
/ 09 мая 2019

У меня есть внешняя библиотека, в которую я передаю экземпляр System.Data.SqlClient.SqlConnection, и я хочу обернуть все, что библиотека делает с этим соединением в транзакции.Когда я работал с php / doctrine, я просто делал именно это в таких случаях - запускал транзакцию в моем коде, вызывал вещи в библиотеке, которая выдает запросы к БД, а затем фиксировал транзакцию в моем коде.Когда я попытался использовать этот подход в C #, я получил следующее исключение:

ExecuteScalar требует, чтобы команда имела транзакцию, когда назначенное команде соединение находится в ожидающей локальной транзакции.Свойство Transaction команды не было инициализировано.

Поэтому я взглянул на код библиотеки, и он всегда использует SqlCommand без установки свойства Transaction.Можно ли как-то достичь моей цели?(изменение кода библиотеки невозможно)

Ответы [ 2 ]

1 голос
/ 09 мая 2019

Вы не опубликовали свой код, но я предполагаю, что вы пытались использовать явную транзакцию, вызвав SqlConnection.BeginTransaction().

Вы можете использовать TransactionScope для создания неявной транзакции. Любое соединение, команда, созданная за время существования TransactionScope, будет автоматически зачислено в транзакцию

Копирование из Реализация неявной транзакции с использованием области действия * Пример :

    // Create the TransactionScope to execute the commands, guaranteeing
    // that both commands can commit or roll back as a single unit of work.
    using (TransactionScope scope = new TransactionScope())
    {
        using (SqlConnection connection1 = new SqlConnection(connectString1))
        {
            // Opening the connection automatically enlists it in the 
            // TransactionScope as a lightweight transaction.
            connection1.Open();

            // Create the SqlCommand object and execute the first command.
            SqlCommand command1 = new SqlCommand(commandText1, connection1);
            returnValue = command1.ExecuteNonQuery();
            writer.WriteLine("Rows to be affected by command1: {0}", returnValue);

            // If you get here, this means that command1 succeeded. By nesting
            // the using block for connection2 inside that of connection1, you
            // conserve server and network resources as connection2 is opened
            // only when there is a chance that the transaction can commit.   
            using (SqlConnection connection2 = new SqlConnection(connectString2))
            {
                // The transaction is escalated to a full distributed
                // transaction when connection2 is opened.
                connection2.Open();

                // Execute the second command in the second database.
                returnValue = 0;
                SqlCommand command2 = new SqlCommand(commandText2, connection2);
                returnValue = command2.ExecuteNonQuery();
                writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
            }
        }

        // The Complete method commits the transaction. If an exception has been thrown,
        // Complete is not  called and the transaction is rolled back.
        scope.Complete();

    }

Соединение и обе команды в этом примере выполняются в рамках одной транзакции. В случае возникновения исключения транзакция будет отменена.

0 голосов
/ 09 мая 2019

В .NET вы можете использовать TransationScope , и все будет происходить в одной транзакции:

using (TransactionScope scope = new TransactionScope())
{
    // Everything inside this block will be transactional:
    // Call the libraries which will use your SqlConnection here
}

Или вы можете использовать BeginTransaction перед вызовом других функций библиотеки и зафиксировать его после вызова функции

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...