Транзакция с чистой точечной сетью
Я хотел бы запустить несколько операторов вставки для нескольких таблиц. Я использую dapper.net. Я не вижу способа обрабатывать транзакции с dapper.net.
Пожалуйста, поделитесь своими идеями о том, как использовать транзакции с dapper.net.
6 ответов
Вот фрагмент кода:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
Обратите внимание, что вам нужно добавить ссылку на System.Transactions
сборка, потому что на нее нет ссылок по умолчанию.
Я предпочел использовать более интуитивный подход, получая транзакцию непосредственно из соединения:
// 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();
}
В Dapper есть 3 подхода к выполнению транзакций.
- Простая транзакция
- Транзакция из области транзакции
- Использование Dapper Transaction ( и наиболее предпочтительный подход)
Вы можете узнать больше об этих подходах к транзакциям на официальном веб-сайте руководства здесь.
Для справки вот разбивка подходов к транзакциям
1. Простая транзакция
В этом примере вы создаете транзакцию в существующем соединении с базой данных, а затем передаете транзакцию методу Execute на dapper (который является необязательным параметром).
Выполнив всю свою работу, просто зафиксируйте транзакцию.
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
connection.Execute(sql, new {CustomerName = "Mark"}, transaction: transaction);
connection.Execute(sql, new {CustomerName = "Sam"}, transaction: transaction);
connection.Execute(sql, new {CustomerName = "John"}, transaction: transaction);
transaction.Commit();
}
}
2. Транзакция из области транзакции
Если вы хотите создать область транзакции, вам нужно будет сделать это до создания соединения с базой данных. После того, как вы создали область транзакции, вы можете просто выполнить все свои операции, а затем выполнить один вызов для завершения транзакции, которая затем зафиксирует все команды.
using (var transaction = new TransactionScope())
{
var sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";
using (var connection = My.ConnectionFactory())
{
connection.Open();
connection.Execute(sql, new {CustomerName = "Mark"});
connection.Execute(sql, new {CustomerName = "Sam"});
connection.Execute(sql, new {CustomerName = "John"});
}
transaction.Complete();
}
3. Использование Dapper Transaction
Это наиболее благоприятный подход для выполнения транзакции в коде, поскольку он упрощает чтение и реализацию кода. Существует расширенная реализация транзакции SQL под названием Dapper Transaction (которую вы можете найти дополнительный пакет nugetздесь ), которая позволяет вам запускать SQL, выполняемый непосредственно из транзакций.
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
transaction.Execute(sql, new {CustomerName = "Mark"});
transaction.Execute(sql, new {CustomerName = "Sam"});
transaction.Execute(sql, new {CustomerName = "John"});
transaction.Commit();
}
}
Вы должны быть в состоянии использовать 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, как описано в этом ответе.
Ответ Даниэля сработал, как и ожидалось для меня. Для полноты приведем фрагмент, демонстрирующий фиксацию и откат с использованием области транзакции и 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