private async Task ApplyCorrection(ApprenticeshipVenueCorrection apprenticeshipVenueCorrection, CancellationToken cancellationToken) { if (!_venueCorrector.Apply(apprenticeshipVenueCorrection)) // mutates apprenticeship directly { return; // no changes to apply } var documentUri = UriFactory.CreateDocumentUri( _configuration.DatabaseId, _configuration.ApprenticeshipCollectionName, apprenticeshipVenueCorrection.Apprenticeship.Id.ToString()); // Dropping to native cosmosdb libraries here rather than cqrs commands because // this gives us a complete round-trip without either: // * introducing another read operation which would be significant on 40k records in terms of time and RU limits, or // * blowing a hole in the command/query api by just exposing ReplaceDocument capability _logger.LogDebug($"{LogPrefix} Replacing apprenticeship document at uri {documentUri} with corrected copy..."); try { var response = await _documentClient.ReplaceDocumentAsync(documentUri, apprenticeshipVenueCorrection.Apprenticeship, new RequestOptions { AccessCondition = new AccessCondition { Type = AccessConditionType.IfMatch, Condition = apprenticeshipVenueCorrection.Apprenticeship.ETag, } }, cancellationToken); if (response.StatusCode != HttpStatusCode.OK) { var failure = $"ReplaceDocument failed for {documentUri}, cosmos responded with status code: {response.StatusCode}"; apprenticeshipVenueCorrection.UpdateFailure = failure; _logger.LogError($"{LogPrefix} {failure}"); } else { apprenticeshipVenueCorrection.UpdatedDate = DateTime.UtcNow; } } catch (Exception exception) { var message = $"{LogPrefix} Error replacing apprenticeship at {documentUri}. {exception.Message}"; apprenticeshipVenueCorrection.UpdateFailure = message; _logger.LogError($"{LogPrefix} {message}", exception); } }
/// <summary> /// Mutates the attached apprenticeship and its locations. /// </summary> /// <param name="apprenticeshipVenueCorrection">Changes to make plus apprenticeship to modify</param> /// <returns>true if any changes made</returns> public bool Apply(ApprenticeshipVenueCorrection apprenticeshipVenueCorrection) { bool dirty = false; foreach (var locationVenueCorrection in apprenticeshipVenueCorrection.ApprenticeshipLocationVenueCorrections .Where(c => c.VenueCorrection != null)) { var locationToUpdate = apprenticeshipVenueCorrection.Apprenticeship.ApprenticeshipLocations .Single(l => l.Id == locationVenueCorrection.LocationId); // mutating the in-memory copy of the apprenticeship directly is a bit nasty, but quicker to do for this throwaway code locationToUpdate.VenueId = locationVenueCorrection.VenueCorrection.Id; locationToUpdate.UpdatedDate = _clock.UtcNow; locationToUpdate.UpdatedBy = "VenueCorrector"; apprenticeshipVenueCorrection.Apprenticeship.UpdatedDate = _clock.UtcNow; apprenticeshipVenueCorrection.Apprenticeship.UpdatedBy = "VenueCorrector"; dirty = true; } return(dirty); }