Як користуватися транзакціями з dapper.net?


106

Я хотів би запускати кілька вкладених операторів у кількох таблицях. Я використовую dapper.net. Я не бачу жодного способу обробити транзакції з dapper.net.

Поділіться своїми ідеями щодо використання транзакцій з dapper.net.

Відповіді:


107

Ось фрагмент коду:

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

Зауважте, що вам потрібно додати посилання на System.Transactionsзбірку, оскільки воно не посилається за замовчуванням.


7
Чи потрібно явно відмовлятися про помилку чи система System.Transaction справляється з цим автоматично?
Норберт Норбертсон

6
@NorbertNorbertson це робить автоматично, Dispose()методом. Якщо Complete()не було викликано, транзакція повертається назад.
the_joric

4
Варто зазначити через іншу відповідь ( stackoverflow.com/a/20047975/47672 ): підключення має бути відкрито всередині TransctionScopeблоку, якщо ви виберете цю відповідь.
0x49D1

2
Дивіться також ( stackoverflow.com/a/20047975/444469 ) - DoYouDapperWork (Виконати запит, і т.д. ...) потребує транзакції в параметрах.
Матьє

Чи відкликається відкат автоматично, якщо є проблеми?
gandalf

91

Я вважав за краще використовувати більш інтуїтивний підхід, отримуючи транзакцію безпосередньо з підключення:

// 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: Ну, ми, мабуть, використовуємо різні рамки Dapper, тому що в цьому є: github.com/StackExchange/dapper-dot-net
andrecarlucci

25
повинні викликати connection.open () перед .begintransaction
Timeless

З'єднання не зараховується автоматично до операції, якщо ви не відкриєте з'єднання в межах транзакційного зонду. Я не знаю, як працює ваш код, якщо GetOpenConnection якось магічно відкриється в межах транзакційного коду, але я б став на те, щоб цього не сталося
Ерік Бергштедт

@ErikBergstedt, ти кажеш, що з'єднання має бути відкритим лише після того, як ми зателефонуємо .BeginTransaction()на нього? Якщо це було так, цей метод розширення сприяв би неправильному використанню транзакції. (IMO, він повинен навіть кинути "не вдається відкрити транзакцію після того, як з'єднання вже відкрите".)
ANeves

2
Добре вказувати транзакцію як параметр Execute, оскільки це потрібно.
Арв Систад

19

Ви повинні мати можливість використовувати, TransactionScopeоскільки Dapper виконує лише команди ADO.NET.

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

8

Зважаючи на те, що всі ваші таблиці знаходяться в одній базі даних, я не погоджуюся з TransactionScopeрішенням, запропонованим у деяких відповідях тут. Зверніться до цієї відповіді.

  1. TransactionScopeзазвичай використовується для розподілених транзакцій; транзакції, що охоплюють різні бази даних, можуть бути в різних системах. Для цього потрібні деякі конфігурації для операційної системи та SQL Server, без яких це не буде працювати. Це не рекомендується, якщо всі ваші запити суперечать одному екземпляру бази даних.
    Але з єдиною базою даних це може бути корисно, коли вам потрібно включити код в транзакції, яка не є вашим контролем. З єдиною базою даних він також не потребує спеціальних конфігурацій.

  2. connection.BeginTransactionє синтаксисом ADO.NET для реалізації транзакцій (у C #, VB.NET тощо) проти однієї бази даних. Це не працює в декількох базах даних.

Отже, connection.BeginTransaction()кращий шлях.

Навіть кращий спосіб впоратися з транзакцією - це реалізувати UnitOfWork, як пояснено у цій відповіді.


4
Для отримання переваги від TransactionScope не потрібно декількох баз даних. Особливою корисністю є те, що він навколишній. Він чудово підходить для упаковки коду, який ви не володієте або не можете змінити, в транзакції. Наприклад, він може бути використаний з великим ефектом, коли код тестування блоку / інтеграції виконує виклики бази даних, куди ви хочете відкотитися. Просто пливіть TransactionScope, перевіряйте код та розпоряджайтесь під час тестового очищення.
Ларрі Сміт

3
@LarrySmith: Погоджено; але питання не в цьому нічого. ОП просто каже, що хоче вставити кілька таблиць за одну транзакцію. Деякі відповіді, включаючи прийнятий, пропонують використовувати TransactionScopeнеефективні для того, що хочуть ОП. Я згоден, що TransactionScopeце гарний інструмент у багатьох випадках; але не це.
Аміт Джоші

5

Відповідь Даніеля спрацювала так, як очікувалося для мене. Для повноти, ось фрагмент, який демонструє фіксацію та відкат, використовуючи область транзакції та даппер:

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, що зводиться до особистих переваг. Я вважаю за краще вперше дізнатися, що щось пішло не так, і не сприймаю заяви журналу як підстилку. Крім того, моя відповідь досі цінує оголошення, демонструючи один із способів використання транзакцій з Dapper
Sudhanshu Mishra

@CodeNaked, по-перше, ви неправильно замовили там. Блок лову буде звернений спочатку, якщо є виняток, а потім кінець області використання. По-друге, подивіться на цю відповідь і на посилається документ MSDN: stackoverflow.com/a/5306896/190476 виклик розпорядження вдруге не є шкідливим; добре розроблений об'єкт ігнорує другий виклик. Спростування не виправдано!
Sudhanshu Mishra

@dotnetguy - Я не намагався повідомити, який Disposeметод називається першим чи другим, тільки що він викликається двічі. Щодо того, що "виклик розпоряджатися вдруге не є шкідливим", це велике припущення. Я дізнався, що документи та фактичні реалізації часто не згодні. Але якщо ви хочете слова Microsoft для цього: msdn.microsoft.com/en-us/library/…
CodeNaked

3
Отже, попередження про аналіз коду є вашою причиною звернути увагу? Це не робить відповідь невірною або оманливою - саме тоді відповідна заява підходить. Чому б вам не відредагувати відповідь і не запропонувати краще рішення, зберігаючи функціональність? Переповнення стека - це вся допомога та конструктивна критика.
Sudhanshu Mishra
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.