2016-08-03 6 views
0

Я использую mehdime/DbContextScope как documented here, чтобы реализовать решение для обновления/импорта массового пользователя для нашего продукта.DbContextScope Transaction

Под заголовком «изменения, сохраняются только тогда, когда SaveChanges() называется», Мехди говорится в примере кода:

Не называйте SaveChanges() до завершения бизнес-операции завершена - т.е. нет частичное или промежуточное сохранение. SaveChanges() необходимо называть ровно один раз за транзакцию.

Если вы окажетесь необходимости вызвать SaveChanges() несколько раз в бизнес-операции, то это означает, что вы на самом деле реализации нескольких бизнес-операций в рамках одного метода обслуживания .

Однако, я хочу добавить новую строку, получить ее сгенерированный идентификатор (столбец IDENTITY), а затем добавить запись журнала аудита в базу данных, ссылающуюся на сгенерированный идентификатор. Для этого мне нужно выполнить промежуточный SaveChanges(), чтобы EF выполнил INSERT и получил идентификатор, однако я хочу сделать это в одной атомной транзакции.

Я что-то упустил или это действительно возможно, не нарушая правила Меджи?

Вот мой пример кода (который в настоящее время нарушает правило)

/// <summary> 
    /// Creates a new Location 
    /// </summary> 
    /// <param name="orgID">ID of Organisation</param> 
    /// <param name="name">Location Name</param> 
    /// <returns></returns> 
    public IActionResult Create(int orgID, string name) 
    { 
     if (string.IsNullOrEmpty(name)) 
      throw new ArgumentNullException(nameof(name)); 

     // New Location 
     var location = new Location { 
      OrganisationID = orgID, 
      Name = name, 
      Enabled = true 
     }; 

     using (var dbContextScope = _dbContextScopeFactory.Create()) 
     { 
      var ctx = dbContextScope.DbContexts.Get<PlatformEntities2014>(); 

      // Duplicate name? 
      var existing = ctx.Locations.Where(l => l.OrganisationID == orgID && l.Name == name).FirstOrDefault(); 
      if (existing != null) 
       return new ActionResult(ActionResultCode.ErrorAlreadyExists) { ReferencedObject = existing }; 

      ctx.Locations.Add(location); 
      // ---POSITION A--- 
      dbContextScope.SaveChanges(); // (Assigns location.ID) 

      // Log 
      GeneralLog log = new GeneralLog() { 
       DateTime = DateTime.Now, 
       Code = "LOC", 
       SubCode = "NEW", 
       OrganisationID = orgID, 
       Information = $"Location {location.ID} \"{location.Name}\" created during Bulk Refresh." 
      }; 
      ctx.GeneralLogs.Add(log); 
      // ---POSITION B--- 
      dbContextScope.SaveChanges(); 

      return new ActionResult(ActionResultCode.Success) { ReferencedObject = location }; 
     } 
    } 

было бы приемлемо, чтобы заменить первый dbContextScope.SaveChanges(); в положении А с ctx.SaveChanges(); для получения идентификатора и вызвать dbContextScope.SaveChanges(); на ПОЗИЦИИ B?

Спасибо.

+0

Как ваши отношения EF настраиваются в контексте. Если они правильно настроены, так как местоположение связано с журналом через отношение внешнего ключа. Вы можете просто вызвать savechanges() в позиции 2, а EF должен автоматически подключить идентификаторы для вас. –

+0

@ Увидеть, к сожалению, как видно из примера кода, таблица «Общий лог» является общим журналом и не имеет прямого отношения к таблице «Местоположение». Мы хотим зарегистрировать идентификатор и имя местоположения в 'Информационное поле varchar (...)'. 'GeneralLog' записывает много информации о множестве разных вещей и не является специфичным для местоположения. Я понимаю ваше предложение, но отношения в этом случае не существуют. –

+0

Должен был прочитать это немного лучше. Хорошо, в этом случае это две отдельные бизнес-операции. Посмотрите на это таким образом, что ваша транзакция не считается неудачной, если она не создает «GeneralLog». Поэтому я бы сказал, что делаю это как две отдельные транзакции. –

ответ

1

Дальше от вашего объяснения, что отношения находятся в комментариях. это две отдельные бизнес-операции. Посмотрите на это таким образом, что ваша транзакция не считается неудачной, если она не создает «GeneralLog». Поэтому я бы сказал, что делаю это как две отдельные транзакции. Ведение журнала не должно приводить к срыву вашей бизнес-транзакции. Вы можете создать объекты сначала в одной транзакции. Получите идентификаторы и создайте журналы в отдельной транзакции.