Bagaimana cara bertransaksi dengan dapper.net?

106

Saya ingin menjalankan beberapa pernyataan penyisipan pada beberapa tabel. Saya menggunakan dapper.net. Saya tidak melihat cara untuk menangani transaksi dengan dapper.net.

Bagikan ide Anda tentang cara menggunakan transaksi dengan dapper.net.

Amit
sumber

Jawaban:

107

Berikut cuplikan kodenya:

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

Perhatikan bahwa Anda perlu menambahkan referensi ke System.Transactionsassembly karena tidak direferensikan secara default.

the_joric
sumber
7
Apakah perlu untuk secara eksplisit memutar kembali kesalahan atau apakah System.Transactions menanganinya secara otomatis?
Norbert Norbertson
6
@NorbertNorbertson melakukannya secara otomatis, dalam Dispose()metode. Jika Complete()belum dipanggil, transaksi akan dibatalkan.
the_joric
4
Layak untuk disebutkan karena jawaban lain ( stackoverflow.com/a/20047975/47672 ): koneksi harus dibuka di dalam TransctionScopeuse block jika Anda memilih jawaban ini.
0x49D1
2
Lihat juga ( stackoverflow.com/a/20047975/444469 ) - DoYouDapperWork (Execute, Query, dll ...) membutuhkan transaksi dalam parameter.
Matthieu
Apakah rollback dipanggil secara otomatis jika ada masalah?
gandalf
91

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();
}
ANeves
sumber
@ANeves: Ya, kami mungkin menggunakan kerangka kerja Dapper yang berbeda, karena yang ini memiliki: github.com/StackExchange/dapper-dot-net
andrecarlucci
25
harus menelepon connection.open () sebelum .begintransaction
Timeless
Koneksi tidak secara otomatis terdaftar di transactioncope kecuali Anda membuka koneksi di dalam transactioncope. Saya tidak tahu bagaimana kode Anda bekerja, jika GetOpenConnection entah bagaimana secara ajaib membuka dirinya sendiri di dalam transactioncope, tetapi saya berani bertaruh bahwa itu tidak
Erik Bergstedt
@ErikBergstedt, apakah Anda mengatakan bahwa koneksi harus terbuka hanya setelah kami memanggilnya .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".)
ANeves
2
Poin yang bagus untuk memasukkan transaksi sebagai parameter Execute, karena ini diperlukan.
Arve Systad
19

Anda harus dapat menggunakan TransactionScopekarena Dapper hanya menjalankan perintah ADO.NET.

using (var scope = new TransactionScope())
{
   // insert
   // insert
   scope.Complete();
}
Daniel A. White
sumber
8

Mengingat semua tabel Anda berada dalam database tunggal, saya tidak setuju dengan TransactionScopesolusi yang disarankan dalam beberapa jawaban di sini. Lihat jawaban ini .

  1. TransactionScopeumumnya 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.

  2. connection.BeginTransactionadalah 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 .

Amit Joshi
sumber
4
Seseorang tidak memerlukan banyak database untuk mendapatkan keuntungan dari TransactionScope. Kegunaan tertentu adalah ambien. Ini bagus untuk membungkus kode yang tidak Anda miliki atau tidak dapat ubah, dalam transaksi. Misalnya dapat digunakan untuk efek yang besar ketika unit / kode pengujian integrasi yang melakukan panggilan database di mana Anda ingin memutar kembali setelahnya. Cukup letakkan TransactionScope, uji kode, dan buang selama pembersihan pengujian.
Larry Smith
3
@LarrySmith: Setuju; tetapi pertanyaannya bukanlah tentang semua ini. OP hanya mengatakan dia ingin memasukkan beberapa tabel dalam satu transaksi. Beberapa jawaban termasuk yang diterima, menyarankan untuk digunakan TransactionScopeyang tidak efisien untuk apa yang diinginkan OP. Saya setuju itu TransactionScopeadalah alat yang bagus dalam banyak kasus; tapi bukan ini.
Amit Joshi
5

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 
Sudhanshu Mishra
sumber
2
@usr yang tergantung pada preferensi pribadi. Saya lebih suka mengetahui saat pertama kali terjadi kesalahan dan tidak melihat pernyataan log sebagai sampah. Juga, jawaban saya masih bernilai iklan dengan mendemonstrasikan satu cara untuk menggunakan transaksi dengan rapi
Sudhanshu Mishra
@CodeNaked, pertama, Anda salah memesan di sana. Blok catch akan dipukul terlebih dahulu jika ada pengecualian, lalu akhir ruang lingkup untuk digunakan. Kedua, lihat jawaban ini dan dokumen MSDN yang direferensikan: stackoverflow.com/a/5306896/190476 memanggil membuang kedua kalinya tidak berbahaya, objek yang dirancang dengan baik mengabaikan panggilan kedua. Suara negatif tidak dibenarkan!
Sudhanshu Mishra
@dotnetguy - Saya tidak mencoba untuk mengkomunikasikan Disposemetode 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/…
CodeNaked
3
Jadi, peringatan analisis kode adalah alasan Anda untuk tidak memilih? Itu tidak membuat jawaban salah atau menyesatkan - saat itulah suara negatif sesuai. Mengapa Anda tidak mengedit jawaban dan mengusulkan solusi yang lebih baik sambil tetap mempertahankan fungsinya? Stack overflow adalah tentang membantu dan kritik yang membangun.
Sudhanshu Mishra