Ответы:
Вот фрагмент кода:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
Обратите внимание, что вам нужно добавить ссылку на System.Transactions
сборку, потому что по умолчанию на нее нет ссылки.
Dispose()
методом. Если Complete()
не был вызван, транзакция откатывается.
TransctionScope
блока using, если вы выберете этот ответ.
Я предпочел использовать более интуитивный подход, получая транзакцию непосредственно из соединения:
// 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();
}
.BeginTransaction()
? Если бы это было так, этот метод расширения способствовал бы неправильному использованию транзакции. (IMO, он должен даже бросить «не удается открыть транзакцию после того, как соединение уже открыто».)
Execute
, если это необходимо.
Вы должны иметь возможность использовать, TransactionScope
поскольку Dapper запускает только команды ADO.NET.
using (var scope = new TransactionScope())
{
// insert
// insert
scope.Complete();
}
Учитывая, что все ваши таблицы находятся в единой базе данных, я не согласен с TransactionScope
решением, предложенным в некоторых ответах здесь. Обратитесь к этому ответу.
TransactionScope
обычно используется для распределенных транзакций; транзакции, охватывающие разные базы данных, могут находиться в разных системах. Это требует некоторых настроек операционной системы и SQL Server, без которых это не будет работать. Это не рекомендуется, если все ваши запросы относятся к одному экземпляру базы данных.
Но с единой базой данных это может быть полезно, когда вам нужно включить код в транзакцию, которая не находится под вашим контролем. С единой базой данных тоже не требуется особых настроек.
connection.BeginTransaction
синтаксис ADO.NET для реализации транзакции (в C #, VB.NET и т. д.) с единой базой данных. Это не работает с несколькими базами данных.
Итак, connection.BeginTransaction()
лучший способ пойти.
Даже лучший способ обработать транзакцию - реализовать UnitOfWork, как описано в этом ответе.
TransactionScope
который неэффективен для того, что хочет OP. Я согласен, что TransactionScope
во многих случаях это хороший инструмент; но не это.
Ответ Дэниела сработал для меня, как и ожидалось. Для полноты, вот фрагмент, который демонстрирует фиксацию и откат с использованием области транзакции и 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
Dispose
метод вызывается первым или вторым, просто он вызывается дважды. Что касается того, что «повторный вызов утилиты не вреден», это большое предположение. Я узнал, что документы и фактические реализации часто не совпадают. Но если вам нужны слова Microsoft: msdn.microsoft.com/en-us/library/…