internal static IEnumerable <SurveyAnswerDelta> GetDeltas( IDictionary <string, object> currentAnswers, IDictionary <string, object> incomingAnswers) { var deltas = new HashSet <SurveyAnswerDelta>(); //all keys should match var nonMatchingKeys = currentAnswers.Keys.Except(incomingAnswers.Keys); if (nonMatchingKeys.Any()) { throw new ArgumentOutOfRangeException( "Expected for current and incoming answer sets to have matching keys. " + $"Instead found '{string.Join(',', nonMatchingKeys)}' keys that were different"); } foreach (var key in currentAnswers.Keys) { dynamic current = currentAnswers[key]; dynamic incoming = incomingAnswers[key]; System.Diagnostics.Debug.WriteLine($"c='{current.GetType()}' i='{incoming.GetType()}'"); //unbox to the correct types if (!SurveyAnswerBindingHelpers.IsQuestion(key) && !SurveyAnswerBindingHelpers.IsRepeater(key)) { if (current is IEnumerable <IHaveUniqueKey> ) { foreach (var delta in DetectChanges(key, current, incoming)) { deltas.Add(delta); } } else { //throw new NotImplementedException(); } } else if (SurveyAnswerBindingHelpers.IsRepeater(key)) { if (!JToken.DeepEquals(current, incoming)) { deltas.Add( new SurveyAnswerDelta(key, current, incoming, AnswerState.Modified)); } } else { if (!Equals(current, incoming)) { deltas.Add( new SurveyAnswerDelta(key, current, incoming, AnswerState.Modified)); } } } return(deltas); }
protected async override Task HandleInnerAsync(SurveyAnswerWriteContext context) { //this should only handle single questions if (!SurveyAnswerBindingHelpers.IsQuestion(context.Delta.Key)) { return; } //handle null if (context.Delta.Incoming == null) { await DeleteAnswer(context); return; } await UpsertAnswer(context, context.Delta.Incoming); }
public async Task Execute(SaveSurveyAnswers command) { var questionStorageMap = await repos.GetQuestionStorageMap(command.SurveyId); var currentAnswers = await repos.Get(new GetSurveyAnswers { CaseId = command.CaseId, SurveyId = command.SurveyId, ProfileId = command.ProfileId, OutbreakId = command.OutbreakId }); //unwrap jArrays to complex types SurveyAnswerBindingHelpers.Bind(command.Answers); var answers = command.Answers.ToDictionary(entry => entry.Key.ToUpper(), entry => entry.Value); //get only the differences var deltas = SurveyAnswerHelpers.GetDeltas(currentAnswers, answers); //if no delta, exit if (!deltas.Any()) { return; } var writer = COR <SurveyAnswerWriteContext> .CreateChain( new SymptomWriteHandler(), new TravelHistoryWriteHandler(), new MappedWriteHandler(dataServices), new RepeaterWriteHandler(), new MultipleWriteHandler(), new DefaultWriteHandler()); var allkeys = deltas .Select(delta => delta.Key) .ToList(); var storageMapping = writeContext.SurveyObjectMapping .Where(mapping => mapping.CdMappingtype == "TARGETDS") .Where(mapping => allkeys.Contains(mapping.IdQuestion)) .ToDictionary(mapping => mapping.IdQuestion.ToUpper()); var surveyInstanceId = await repos.GetSurveyInstanceId(command.ProfileId, command.CaseId, command.OutbreakId); var connection = writeContext.Database.GetDbConnection().EnsureOpen(); using (var transaction = writeContext.Database.BeginTransaction().GetDbTransaction()) { //TODO: This needs better DB design //if no survey instance, create one if (surveyInstanceId == 0) { surveyInstanceId = (int)await sequencerGenerator.GetNextAsync(SequenceType.SurveyInstance); var instance = new SurveyInstance { IdSurveyInstance = surveyInstanceId.Value, IdProfile = command.ProfileId, }; if (command.OutbreakId != null) { instance.CdEntityType = "O"; instance.IdEntity = command.OutbreakId; } if (command.CaseId != null) { instance.CdEntityType = "C"; instance.IdEntity = command.CaseId; } await writeContext.SurveyInstance.AddAsync(instance); await writeContext.SaveChangesAsync(); } //end var context = new SurveyAnswerWriteContext { DB = writeContext, CaseId = command.CaseId, ProfileId = command.ProfileId, OutbreakId = command.OutbreakId, SurveyInstanceId = surveyInstanceId.Value, //should be assigned a value by this point UserId = usernameProvider.GetUsername(), Timestamp = DateTime.Now, QuestionStorageMap = questionStorageMap }; context.Transaction = transaction; context.Connection = connection; //apply the changes foreach (var delta in deltas) { context.Delta = delta; await writer.HandleAsync(context); //need to mark question as answered if (SurveyAnswerBindingHelpers.IsQuestion(delta.Key)) { var param = new { questionId = delta.Key }; try { string sql = @"update survey_question_bank set IN_ANSWERED = 1 where id_question = @questionId and IN_ANSWERED = 0;"; await connection.ExecuteAsync(sql, param, 1, transaction); } catch (Exception e) { //do nothing for now } } } transaction.Commit(); } }