#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
… Фактически то, что вы написали выше. Я искренне благодарен вам за помощь… Спасибо!