Jawaban:
Berikut cuplikan kodenya:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
Perhatikan bahwa Anda perlu menambahkan referensi ke System.Transactions
assembly karena tidak direferensikan secara default.
Dispose()
metode. Jika Complete()
belum dipanggil, transaksi akan dibatalkan.
TransctionScope
use block jika Anda memilih jawaban ini.
Saya lebih suka menggunakan pendekatan yang lebih intuitif dengan mendapatkan transaksi langsung dari koneksi:
// 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()
? Jika itu masalahnya, metode ekstensi ini akan mempromosikan penggunaan transaksi yang salah. (IMO, bahkan harus membuang "tidak dapat membuka transaksi setelah koneksi sudah terbuka".)
Execute
, karena ini diperlukan.
Anda harus dapat menggunakan TransactionScope
karena Dapper hanya menjalankan perintah ADO.NET.
using (var scope = new TransactionScope())
{
// insert
// insert
scope.Complete();
}
Mengingat semua tabel Anda berada dalam database tunggal, saya tidak setuju dengan TransactionScope
solusi yang disarankan dalam beberapa jawaban di sini. Lihat jawaban ini .
TransactionScope
umumnya digunakan untuk transaksi terdistribusi; transaksi yang mencakup database yang berbeda mungkin pada sistem yang berbeda. Ini membutuhkan beberapa konfigurasi pada sistem operasi dan SQL Server yang tanpanya ini tidak akan berfungsi. Ini tidak disarankan jika semua kueri Anda bertentangan dengan satu contoh database.
Tapi, dengan database tunggal ini mungkin berguna ketika Anda perlu memasukkan kode dalam transaksi yang tidak di bawah kendali Anda. Dengan database tunggal, tidak memerlukan konfigurasi khusus juga.
connection.BeginTransaction
adalah sintaks ADO.NET untuk mengimplementasikan transaksi (di C #, VB.NET dll.) terhadap database tunggal. Ini tidak bekerja di beberapa database.
Begitu, connection.BeginTransaction()
cara yang lebih baik untuk pergi.
Bahkan cara yang lebih baik untuk menangani transaksi adalah dengan mengimplementasikan UnitOfWork seperti yang dijelaskan dalam jawaban ini .
TransactionScope
yang tidak efisien untuk apa yang diinginkan OP. Saya setuju itu TransactionScope
adalah alat yang bagus dalam banyak kasus; tapi bukan ini.
Jawaban Daniel bekerja seperti yang diharapkan untuk saya. Untuk kelengkapan, berikut cuplikan yang menunjukkan commit dan rollback menggunakan cakupan transaksi dan rapi:
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
metode mana yang dipanggil pertama atau kedua, hanya saja itu dipanggil dua kali. Mengenai poin bahwa "menelepon untuk kedua kalinya tidak berbahaya", itu adalah asumsi besar. Saya telah mempelajari bahwa dokumen dan implementasi sebenarnya sering tidak setuju. Tetapi jika Anda ingin kata Microsoft untuk itu: msdn.microsoft.com/en-us/library/…