Làm thế nào để sử dụng các giao dịch với dapper.net?


106

Tôi muốn chạy nhiều câu lệnh chèn trên nhiều bảng. Tôi đang sử dụng dapper.net. Tôi không thấy bất kỳ cách nào để xử lý các giao dịch với dapper.net.

Vui lòng chia sẻ ý kiến ​​của bạn về cách sử dụng giao dịch với dapper.net.

Câu trả lời:


107

Đâ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.Transactionsassembly vì nó không được tham chiếu theo mặc định.


7
Có cần phải khôi phục lỗi một cách rõ ràng hay System.Transactions tự động xử lý điều đó?
Norbert Norbertson

6
@NorbertNorbertson nó thực hiện nó tự động theo Dispose()phương thức. Nếu Complete()chưa được gọi, giao dịch sẽ được khôi phục.
the_joric

4
Đáng được đề cập vì một câu trả lời khác ( stackoverflow.com/a/20047975/47672 ): kết nối phải được mở bên trong TransctionScopekhối using trong trường hợp bạn chọn câu trả lời này.
0x49D1

2
Xem thêm ( stackoverflow.com/a/20047975/444469 ) - DoYouDapperWork (Thực thi, Truy vấn, v.v.) cần giao dịch trong các tham số.
Matthieu

Việc khôi phục có được gọi tự động nếu có sự cố không?
gandalf

91

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();
}

@ANeves: Vâng, chúng tôi đang thể sử dụng khuôn khổ Dapper khác nhau, bởi vì chương trình này có: github.com/StackExchange/dapper-dot-net
andrecarlucci

25
phải gọi connection.open () trước .begintransaction
Timeless

Một kết nối không được tự động sử dụng trong giao dịch trừ khi bạn mở kết nối trong giao dịch. Tôi không biết làm thế nào mã của bạn hoạt động, nếu GetOpenConnection bằng cách nào đó kỳ diệu sẽ mở ra bản thân trong TransactionScope, nhưng tôi muốn cược rằng nó không
Erik Bergstedt

@ErikBergstedt, đang nói rằng kết nối phải được mở chỉ sau khi chúng tôi gọi .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ở".)
ANeves

2
Điểm tốt để bao gồm giao dịch làm tham số Execute, vì điều này là bắt buộc.
Arve Systad

19

Bạn sẽ có thể sử dụng TransactionScopevì Dapper chỉ chạy các lệnh ADO.NET.

using (var scope = new TransactionScope())
{
   // insert
   // insert
   scope.Complete();
}

8

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 TransactionScopegiả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 .

  1. TransactionScopethườ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.

  2. connection.BeginTransactionlà 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 .


4
Người ta không cần nhiều cơ sở dữ liệu để hưởng lợi từ TransactionScope. Đặc biệt tiện ích là môi trường xung quanh. Nó tuyệt vời để gói mã mà bạn không sở hữu hoặc không thể sửa đổi, trong một giao dịch. Ví dụ, nó có thể được sử dụng để tạo ra hiệu quả tuyệt vời khi mã kiểm tra đơn vị / tích hợp thực hiện lệnh gọi cơ sở dữ liệu đến nơi bạn muốn quay lại sau. Chỉ cần thả nổi một TransactionScope, kiểm tra mã và loại bỏ trong quá trình dọn dẹp kiểm tra.
Larry Smith

3
@LarrySmith: Đồng ý; nhưng câu hỏi không phải về bất cứ điều gì trong số này. OP chỉ nói rằng anh ấy muốn chèn nhiều bảng trong một giao dịch. Một số câu trả lời bao gồm câu được chấp nhận, đề nghị sử dụng câu trả lời TransactionScopekhông hiệu quả cho những gì OP muốn. Tôi đồng ý rằng đó TransactionScopelà công cụ tốt trong nhiều trường hợp; nhưng không phải cái này.
Amit Joshi,

5

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 

2
@usr tùy thuộc vào sở thích cá nhân. Tôi muốn biết lần đầu tiên có sự cố xảy ra và không xem các báo cáo nhật ký là rác. Ngoài ra, câu trả lời của tôi vẫn quảng cáo có giá trị bằng cách trình bày một cách để sử dụng giao dịch với dapper
Sudhanshu Mishra

@CodeNaked, trước tiên, bạn đã đặt sai ở đó. Khối bắt sẽ được nhấn đầu tiên nếu có một ngoại lệ, sau đó sẽ kết thúc phạm vi sử dụng. Thứ hai, hãy xem câu trả lời này và tài liệu MSDN được tham chiếu: stackoverflow.com/a/5306896/190476 gọi vứt bỏ lần thứ hai không có hại, một đối tượng được thiết kế tốt sẽ bỏ qua lệnh gọi thứ hai. Phản đối không hợp lý!
Sudhanshu Mishra

@dotnetguy - Tôi không cố gắng truyền đạt Disposephươ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/…
CodeNaked

3
Vì vậy, một cảnh báo phân tích mã là lý do bạn không đồng ý? Điều đó không làm cho câu trả lời sai hoặc gây hiểu lầm - đó là khi một phiếu giảm giá là phù hợp. Tại sao bạn không chỉnh sửa câu trả lời và đề xuất một giải pháp tốt hơn trong khi vẫn giữ nguyên chức năng? Tràn ngăn xếp là tất cả về sự giúp đỡ và phê bình mang tính xây dựng.
Sudhanshu Mishra
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.