Câu trả lời:
Đây là đoạn mã:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
Lưu ý rằng bạn cần thêm tham chiếu vào System.Transactions
assembly vì nó không được tham chiếu theo mặc định.
Dispose()
phương thức. Nếu Complete()
chưa được gọi, giao dịch sẽ được khôi phục.
TransctionScope
khối using trong trường hợp bạn chọn câu trả lời này.
Tôi muốn sử dụng một cách tiếp cận trực quan hơn bằng cách nhận giao dịch trực tiếp từ kết nối:
// 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()
vào nó? Nếu đúng như vậy, phương thức mở rộng này sẽ thúc đẩy việc sử dụng sai giao dịch. (IMO, nó thậm chí sẽ ném "không thể mở giao dịch sau khi kết nối đã được mở".)
Execute
, vì điều này là bắt buộc.
Bạn sẽ có thể sử dụng TransactionScope
vì Dapper chỉ chạy các lệnh ADO.NET.
using (var scope = new TransactionScope())
{
// insert
// insert
scope.Complete();
}
Xem xét tất cả các bảng của bạn đều nằm trong một cơ sở dữ liệu duy nhất, tôi không đồng ý với TransactionScope
giải pháp được đề xuất trong một số câu trả lời ở đây. Tham khảo câu trả lời này .
TransactionScope
thường được sử dụng cho các giao dịch phân tán; giao dịch bao gồm các cơ sở dữ liệu khác nhau có thể trên hệ thống khác nhau. Điều này cần một số cấu hình trên hệ điều hành và SQL Server nếu thiếu nó sẽ không hoạt động. Điều này không được khuyến nghị nếu tất cả các truy vấn của bạn đều dựa trên một phiên bản cơ sở dữ liệu.
Tuy nhiên, với một cơ sở dữ liệu duy nhất, điều này có thể hữu ích khi bạn cần đưa mã vào giao dịch không nằm trong tầm kiểm soát của bạn. Với cơ sở dữ liệu duy nhất, nó cũng không cần cấu hình đặc biệt.
connection.BeginTransaction
là cú pháp ADO.NET để thực hiện giao dịch (trong C #, VB.NET, v.v.) đối với cơ sở dữ liệu đơn lẻ. Điều này không hoạt động trên nhiều cơ sở dữ liệu.
Vì vậy, connection.BeginTransaction()
là cách tốt hơn để đi.
Thậm chí, cách tốt hơn để xử lý giao dịch là thực hiện UnitOfWork như được giải thích trong câu trả lời này .
TransactionScope
không hiệu quả cho những gì OP muốn. Tôi đồng ý rằng đó TransactionScope
là công cụ tốt trong nhiều trường hợp; nhưng không phải cái này.
Câu trả lời của Daniel đã làm việc như mong đợi đối với tôi. Để có sự hoàn chỉnh, đây là một đoạn mã thể hiện cam kết và khôi phục bằng cách sử dụng phạm vi giao dịch và 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
phương thức nào được gọi là thứ nhất hay thứ hai, chỉ là nó được gọi hai lần. Về vấn đề "gọi vứt bỏ lần thứ hai không có hại", đó là một giả định lớn. Tôi đã biết rằng tài liệu và cách triển khai thực tế thường không thống nhất với nhau. Nhưng nếu bạn muốn từ của Microsoft cho nó: msdn.microsoft.com/en-us/library/…