Исключение при попытке создать / использовать внутреннюю транзакцию - PullRequest
1 голос
/ 14 декабря 2010

Мое приложение (служба WCF) использует контексты данных LINQ, и недавно мы решили обернуть все в транзакцию. Кажется, работает довольно хорошо; каждый вызов в сервисе имеет свою собственную транзакцию, поэтому, если выдается исключение, все откатывается, и в базу данных не вносятся никакие изменения.

Однако у нас есть понятие «код супервизора», который можно создавать и использовать только один раз. Мы хотим, чтобы код супервизора был помечен как используемый, даже если ошибка произойдет позже в операции. Для меня это говорит о том, что я должен использовать внутреннюю транзакцию?

Итак, внутри моего SetToUsed метода я ввел новую транзакцию, например, так:

    public void SetToUsed(string code)
    {
        // security codes explicitly need their own transaction so that they will still be marked as having been used even if the outer transaction were to be rolled back due to error
        using (var securityCodeTransaction = new TransactionScope(
                TransactionScopeOption.RequiresNew,
                new TransactionOptions
                {
                    IsolationLevel = IsolationLevel.ReadUncommitted
                },
                EnterpriseServicesInteropOption.Automatic))
        {
            var returnedItems = m_safetyCodeRepository.FindAll(sc => sc.safetyCode == code &&
                                                                     sc.safetyCodeTypeId == (long)GetCodeType() &&
                                                                     sc.isUsed == false);
            foreach (var item in returnedItems)
            {
                item.isUsed = true;
                m_safetyCodeRepository.SaveChanges(item);
            }

            securityCodeTransaction.Complete();
        }
    }

Однако это вызывает исключение: System.InvalidOperationException: Connection currently has transaction enlisted. Finish current transaction and retry.
Исключение выдается в строке FindAll, которая является тонкой оболочкой для

dataContext.GetTable<tbSftSafetyCodes>().Where(exp).ToList()

Я что-то упускаю или поступаю по этому поводу совершенно неправильно?

Редактировать: я понял, что на самом деле мне не нужна транзакция для изменений кода руководителя как таковых.
Поэтому я изменил TransactionScopeOption на TransactionScopeOption.Suppress. Я все еще хотел бы знать, почему внутренняя транзакция с использованием TransactionScopeOption.RequiresNew не сработала!

Ответы [ 2 ]

4 голосов
/ 14 декабря 2010
TransactionScopeOption.RequiresNew    

пытается начать совершенно новую транзакцию, которая не зависит от той, в которой она находится, это то, что вы намереваетесь?Опция Требуется подключит новую транзакцию к текущей активной.

Однако, если yopu всегда хочет, чтобы код был помечен как использованный - нужно ли его вообще включать в транзакцию?Не могли бы вы просто пометить его как использованный и зафиксировать это изменение непосредственно перед началом операции с переносом транзакции?

0 голосов
/ 01 апреля 2015

В моем случае, кроме использования опции TransactionScopeOption.RequiresNew, также необходимо было предшествовать оператору использования с

    dc.Connection.Open();
    dc.Connection.EnlistTransaction(Transaction.Current);
    if (dc.Connection.State!=ConnectionState.Closed) dc.Connection.Close();

    using (var securityCodeTransaction = new TransactionScope(
            TransactionScopeOption.RequiresNew,
            new TransactionOptions
            {
                IsolationLevel = IsolationLevel.ReadUncommitted
            },
            EnterpriseServicesInteropOption.Automatic))
    {
            // same code as in question
    }

Это заставило проблему исчезнуть - однако я понятия не имею, почему это было необходимо.

Примечание: Чтобы подключить транзакцию, соединение должно быть открыто - следовательно, требуются операторы open + close.

...