Вопрос по c# – транзакция с чистой точечной сетью

93

Я хотел бы запустить несколько операторов вставки для нескольких таблиц. Я использую dapper.net. Я не вижу способа обрабатывать транзакции с помощью dapper.net.

Пожалуйста, поделитесь своими идеями о том, как использовать транзакции с dapper.net.

Ваш Ответ

5   ответов
17

TransactionScope так как Dapper запускает только команды ADO.NET.

using (var scope = new TransactionScope())
{
   // insert
   // insert
   scope.Complete();
}
4

как и ожидалось. Для полноты, вот фрагмент, который демонстрирует фиксацию и откат с использованием области транзакции и dapper:

using System.Transactions;
    // _sqlConnection has been opened elsewhere in preceeding code 
    using (var transactionScope = new TransactionScope())
    {
        try
        {
            long result = _sqlConnection.ExecuteScalar<long>(sqlString, new {Param1 = 1, Param2 = "string"});

            transactionScope.Complete();
        }
        catch (Exception exception)
        {
            // Logger initialized elsewhere in code
            _logger.Error(exception, $"Error encountered whilst executing  SQL: {sqlString}, Message: {exception.Message}")

            // re-throw to let the caller know
            throw;
        }
    } // This is where Dispose is called 
@dotnetguy - я не пытался сообщить, какиеDispose метод вызывается первым или вторым, просто он вызывается дважды. Что касается того, что «вызов утилизирует второй раз» не является «вредным», то это большое предположение. Я узнал, что документы и фактические реализации часто не согласны. Но если вам нужно слово Microsoft для этого:msdn.microsoft.com/en-us/library/…
Итак, предупреждение анализа кода - это ваша причина понижать голос? Это не делает ответ неправильным или вводящим в заблуждение - это когда уместно понижать голос. Почему бы вам не отредактировать ответ и не предложить лучшее решение, сохранив при этом функциональность? Переполнение стека - все о помощи и конструктивной критике.
@usr, который сводится к личным предпочтениям. Я предпочитаю знать, когда в первый раз что-то пошло не так, и не вижу в логах помета. Кроме того, мой ответ по-прежнему имеет ценность рекламы, демонстрируя один из способов использования транзакций с dapper
@ CodeNaked, во-первых, у вас там неправильный порядок. Сначала будет обработан блок catch, если есть исключение, а затем конец области применения. Во-вторых, посмотрите на этот ответ и документацию MSDN, на которую ссылаются:stackoverflow.com/a/5306896/190476 Вызов утилизировать во второй раз не вреден, хорошо спроектированный объект игнорирует второй вызов. Понижение не оправдано!
7

что все ваши таблицы находятся в одной базе данных, я не согласен сTransactionScope Решение предлагается в некоторых ответах здесь. обращатьсяэтот ответ.

TransactionScope is generally used for distributed transactions; transaction spanning different databases may be on different system. This needs some configurations on operating system and SQL Server without which this will not work. This is not recommended if all your queries are against single instance of database.
But, with single database this may be useful when you need to include the code in transaction that is not under your control. With single database, it does not need special configurations either.

connection.BeginTransaction is ADO.NET syntax to implement transaction (in C#, VB.NET etc.) against single database. This does not work across multiple databases.

Так,connection.BeginTransaction() это лучший способ пойти.

Даже лучший способ обработать транзакцию - реализовать UnitOfWork, как описано вэтот ответ.

@LarrySmith: согласен; но вопрос не об этом. ОП просто говорит, что хочет вставить несколько таблиц в одну транзакцию. Некоторые ответы, в том числе принятые, предлагают использоватьTransactionScope что неэффективно для того, что хотят ОП. я согласна с тем чтоTransactionScope хороший инструмент во многих случаях; но не это.
Для использования TransactionScope не требуется нескольких баз данных. Особая полезность состоит в том, что это окружающее. Это отлично подходит для упаковки кода, который вы не имеете или не можете изменить в транзакции. Например, это может быть эффективно использовано при тестировании кода модуля / интеграции, который выполняет вызовы базы данных, когда вы хотите выполнить откат после. Просто отправьте TransactionScope, протестируйте код и утилизируйте его во время очистки.
90

using System.Transactions;    
....    
using (var transactionScope = new TransactionScope())
{
    DoYourDapperWork();
    transactionScope.Complete();
}

Обратите внимание, что вам нужно добавить ссылку наSystem.Transactions сборка, потому что на нее нет ссылок по умолчанию.

Смотрите также (stackoverflow.com/a/20047975/444469) - DoYouDapperWork (Execute, Query и т. Д.) Нуждается в транзакции в параметрах.
@NorbertNorbertson это делает это автоматически, вDispose() метод. ЕслиComplete() не был вызван, транзакция откатывается.
Нужно ли явно откатываться при ошибке или System.Transactions обрабатывает это автоматически?
Откат вызывается автоматически, если есть проблема?
Стоит упомянуть из-за другого ответа (stackoverflow.com/a/20047975/47672): соединение должно быть открыто внутриTransctionScope используя блок в случае, если вы выберете этот ответ.
86

получая транзакцию непосредственно из соединения:

// This called method will get a connection, and open it if it's not yet open.
using (var connection = GetOpenConnection())
using (var transaction = connection.BeginTransaction())
{
    connection.Execute(
        "INSERT INTO data(Foo, Bar) values (@Foo, @Bar);", listOf5000Items, transaction);
    transaction.Commit();
}
Полезно включить транзакцию в качестве параметра вExecute, как это требуется.
должен вызывать connection.open () перед .begintransaction
@ ANeves: Ну, мы, вероятно, используем разные фреймворки Dapper, потому что у этого есть:github.com/StackExchange/dapper-dot-net
Соединение не зачисляется в транзакции автоматически, если вы не откроете соединение в транзакции. Я не знаю, как работает ваш код, если GetOpenConnection каким-то волшебным образом открывает себя внутри транзакции, но я уверен, что он этого не делает.
@ErikBergstedt, вы говорите, что связьmust быть открытымonly after мы называем.BeginTransaction() в теме? Если бы это было так, этот метод расширения будет способствовать неправильному использованию транзакции. (IMO, он должен даже выдать "не может открыть транзакцию после того, как соединение уже открыто".)

Похожие вопросы