Шаблон репозитория с MongoDB - несколько единиц работы с одной транзакцией - PullRequest
7 голосов
/ 28 апреля 2019

Я реализую слой абстракции DAL поверх драйвера C # Mongo DB, используя шаблон Repository + Unit of Work.Мой текущий дизайн состоит в том, что каждая единица работы открывает (и закрывает) новый сеанс Mongo DB.Проблема заключается в том, что Mongo DB допускает только соотношение 1: 1 между сеансом и транзакцией, поэтому несколько единиц работы в рамках одной транзакции .NET будут невозможны.

Текущая реализация:

public class MongoUnitOfWork
{
    private IClientSessionHandle _sessionHandle;

    public MongoUnitOfWork(MongoClient mongoClient)
    {
       _sessionHandle = mongoClient.StartSession();
    }

    public void Dispose()
    {
       if (_sessionHandle != null)
       {
          // Must commit transaction, since the session is closing
          if (Transaction.Current != null)
            _sessionHandle.CommitTransaction();
          _sessionHandle.Dispose();
       }
    }
}

И из-за этого следующий код не будет работать.Первая партия данных будет передана заранее:

using (var transactionScope = new TransactionScope())
{
    using (var unitOfWork = CreateUnitOfWork())
    {
       //... insert items

       unitOfWork.SaveChanges();
    }  // Mongo DB unit of work implementation will commit the changes when disposed

    // Do other things

    using (var unitOfWork = CreateUnitOfWork())
    {
       //... insert some more items
       unitOfWork.SaveChanges();
    }
    transactionScope.Complete();
}

Очевидно, что немедленным ответом будет объединение всех изменений в одну единицу работы, но это не всегда возможно, а также это приводит к утечкеОграничение Mongo DB.

Я думал о пуле сеансов, так что несколько единиц работы будут использовать один и тот же сеанс и фиксировать / откатывать, когда временная транзакция завершается / прерывается.

Какие есть другие решениявозможно?

Пояснение:

Вопрос здесь конкретно касается реализации Unit-Of-Work над MongoDB с использованием встроенной поддержки транзакций MongoDB 4.0 (или более поздней).

1 Ответ

6 голосов
/ 29 апреля 2019

Я никогда не использовал MongoDB;ничего не знаю об этом.Я отвечаю только с точки зрения TransactionScope;поэтому не уверен, поможет ли это вам.

Пожалуйста, обратитесь к Magic Of TransactionScope .ИМО, есть три фактора, которые вы должны искать:

  1. Соединение с базой данных должно быть открыто внутри TransactionScope.

    Помните, что соединение должно быть открыто внутри блока TransactionScope, чтобы оно автоматически подключалось к транзакции окружения.Если соединение было открыто до этого, оно не будет участвовать в транзакции.

    Не уверен, но похоже, что вы можете подключить вручную соединение, открытое вне области, используя connection.EnlistTransaction(Transaction.Current).

    Глядя на ваш комментарий и правку, это не проблема.

  2. Все операции должны выполняться в одном потоке.

    Окружающая транзакция, предоставляемая TransactionScope, является статической переменной потока (TLS).Доступ к нему можно получить с помощью статического свойства Transaction.Current.Вот код TransactionScope по адресу referenceource.microsoft.com.ThreadStatic ContextData, содержит CurrentTransaction.

    и

    Помните, что Transaction.Current является статической переменной потока.Если ваш код выполняется в многопоточной среде, вам может потребоваться принять некоторые меры предосторожности.Соединения, которые должны участвовать в окружающих транзакциях, должны быть открыты в том же потоке, который создает TransactionScope, управляющий этой окружающей транзакцией.

    Итак, все операции должны выполняться в одном потоке.

  3. Поиграйте с TransactionScopeOption (передайте его конструктору TransactionScope) в соответствии с вашими потребностями.

    После создания TransactionScope с помощью оператора new менеджер транзакций определяет, в какой транзакции участвовать. После определения область действия всегда участвует в этой транзакции.Решение основывается на двух факторах: присутствует ли окружающая транзакция и значение параметра TransactionScopeOption в конструкторе.

    Я не уверен, что ожидается от вашего кода.Вы можете играть с этими значениями перечисления.

Как вы упомянули в комментарии, вы используете async/await.

Наконец, если вы используете асинхронный/ await внутри блока TransactionScope, вы должны знать, что он плохо работает с TransactionScope, и вы можете захотеть взглянуть на новый конструктор TransactionScope в .NET Framework 4.5.1, который принимает TransactionScopeAsyncFlowOption.Параметр TransactionScopeAsyncFlowOption.Enabled, который не является значением по умолчанию, позволяет TransactionScope хорошо играть с асинхронными продолжениями.

Для MongoDB посмотрите, поможет ли это .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...