Почему я получаю ошибку при использовании TransactionScope?

#c# #ado.net #odbc #transactionscope

#c# #ado.net #odbc #TransactionScope

Вопрос:

Все!

У меня возникли проблемы с TransactionScope. Я хочу, чтобы мой веб-метод был транзакционным. Если возникает какое-либо исключение, я хочу, чтобы все изменения базы данных были отменены. В противном случае зафиксируйте. Пожалуйста, смотрите Сообщение об ошибке ниже.

Система.Исключение ApplicationException: ошибка в SomeClass :: Method public ReturnType methodName(параметр ParameterType) :

Система.Исключение ApplicationException: ошибка в SomeClass :: Метод частной строки someMethod() :

System.Data.odbc.OdbcException (0x80131937):

ОШИБКА [08003] [Sybase] [Драйвер ODBC] Соединение не открыто

в System.Data.odbc.OdbcConnection.Open_EnlistTransaction (транзакция транзакции)

в System.Data.Odbc.OdbcConnectionOpen.EnlistTransaction(транзакция транзакции)

в System.Data.odbc.OdbcConnection.EnlistTransaction(транзакция транзакции)

в System.Data.odbc.OdbcConnection.Открыть ()

в SomeNamespace.someMethod() в c:somePathsomeClass.cs:line 35

Ниже приведен отрывок моего кода. Что я делаю не так?

  [WebMethod]
 public returnType methodName(parameterType parameter)
 {
     using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
     {
         try
         {
             var someValue = someMethod();
                 :
                 :
                 :

             transactionScope.Complete();

             return response;
         }
         catch (Exception ex)
         {
             return ErrorMessages(ex);
         }
     }
 }

 private string someMethod()
 {
     var commandText = "...some valid SQL expression...";
     var commandType = CommandType.Text;

     try
     {
         using (var odbcConnection = new OdbcConnection(DefaultDbConnection.ToString()))
         {
             using (var odbcCommand = new OdbcCommand(commandText, odbcConnection))
             {
                 odbcConnection.Open();  // Exception is thrown here!
                 odbcCommand.CommandType = commandType;

                 using (var reader = odbcCommand.ExecuteReader())
                 {
                     reader.Read();
                     return reader.GetString(0);
                 }
             }
         }
     }
     catch (Exception ex)
     {
         throw new ApplicationException("Error in someMethod.", ex);
     }
 }
 

Заранее благодарю вас за помощь!

Комментарии:

1. Предположительно, вы хотите сказать, что один и тот же код прекрасно работает без области транзакции, не так ли? В конечном счете: не все провайдеры поддерживают этот API, и я бы все равно не советовал этого делать . Что это за штука, с которой ты здесь разговариваешь? (Это очень трудно понять с помощью ODBC, поскольку это резервный устаревший API). Обратите внимание, что вы могли бы попробовать переместить вызов Open() над конструкцией команды.

2. Привет, Марк !… Спасибо за ваш быстрый ответ. Я так рад, что моя проблема привлекла ваше внимание. Я надеялся, что вы ответите. Я видел много ваших ответов. Я всегда нахожу их полезными…

3. Когда я комментирую «использование (var TransactionScope = new TransactionScope ())» и «TransactionScope. Завершите ()» строки, веб-метод работает отлично, точно так, как ожидалось, без ошибок или предупреждений. Только когда я ввожу TransactionScope, «OdbcConnection. Open()» выдает следующее исключение, когда OdbcConnection пытается подключить транзакцию: System.Data.Odbc.OdbcException (0x80131937): ОШИБКА [08003] [Sybase] [Драйвер ODBC] Соединение не открыто

4. Я попробовал следующее… используя (var TransactionScope = new TransactionScope()) используя (var TransactionScope = new TransactionScope(TransactionScopeOption. Обязательно)) // по умолчанию используется (var TransactionScope = new TransactionScope(TransactionScopeOption. Требуется новое)) Ни один из них не работает.

5. Я пробовал «OdbcConnection. Откройте ()» перед «использованием (var odbcccommand = new odbcccommand(CommandText, OdbcConnection))». Это тоже не сработало.

Ответ №1:

В конечном счете, не все типы соединений — и не все платформы — поддерживают транзакции на основе области транзакций, и даже когда они это делают: они могут быть непредсказуемыми из-за проблем с областью видимости при общении с несколькими системами, требующих таких вещей, как DTC.

Вместо этого я бы настоятельно рекомендовал просто: не используйте область транзакции (если у вас нет очень веской причины). Вместо этого предпочитайте гораздо более простой и широко поддерживаемый ADO.NET модель транзакции:

  • используйте BeginTransaction (или асинхронный эквивалент) в соединении, чтобы (что неудивительно) начать транзакцию
  • перенесите этот экземпляр транзакции в код
  • установите свойство transaction для каждой команды (я никогда не понимал, зачем это было бы необходимо, учитывая, что это подразумевается через соединение, но: это так)
  • обязательно зафиксируйте или прервите транзакцию в конце, в идеале используя try / catch / finally , чтобы это происходило правильно как при успешном, так и при неудачном выполнении

Комментарии:

1. Основываясь на вашем предыдущем ответе, я решил отказаться от TransactionScope и сделать это «старомодным» способом… Используя BeginTransaction и try / catch / finally … Фактически то, что вы написали выше. Я искренне благодарен вам за помощь… Спасибо!