/// <summary> /// Merges the specified <paramref name="submission"/> into the repository backed by the <paramref name="provider"/>. /// </summary> /// <param name="submission"> /// The submission. /// </param> /// <param name="provider"> /// The provider. /// </param> private void MergeSubmission(GenericSubmission submission, IRepositoryProvider provider) { // Merge our existing fields var fields = submission.SubmissionValues.Select(value => value.Field).Distinct().ToList(); var fieldItems = from f in fields select new FieldRow { Name = f.Name, Description = f.Description }; // Merge in the field values. var commandProvider = new JsonCommandFactory(); var transaction = provider.BeginTransaction(); var fieldsCommand = new JsonInsert <FieldRow>(provider.DatabaseContext).OnConflict(row => row.Name) .Upsert(row => row.Description) .Returning(row => row.FieldId, row => row.Name, row => row.Description); var mergedFields = fieldsCommand.ExecuteForResults(fieldItems).ToList(); foreach (var field in fields) { var input = mergedFields.FirstOrDefault(f => string.Equals(f.Name, field.Name, StringComparison.Ordinal)); // Because we are doing a subset, and we know we will get back baseline fields. If MERGE is messed up this will error later when there // aren't IDs for baseline fields. if (input == null) { continue; } this.mapper.MapTo(input, field); } var submissionRepository = new EntityRepository <GenericSubmission, GenericSubmissionRow>(provider, this.mapper); submissionRepository.Save(submission); // Could be mapped as well. var fieldValues = from v in submission.SubmissionValues select new FieldValueTableTypeRow { FieldId = v.Field.FieldId.GetValueOrDefault(), LastModifiedByDomainIdentifierId = v.LastModifiedBy.DomainIdentityId.GetValueOrDefault(), LastModifiedTime = v.LastModifiedTime }; // We use FieldValueId to essentially ensure we're only affecting the scope of this submission. FieldId on the select brings back // only inserted rows matched back to their original fields. var fieldValueCommand = new JsonInsert <FieldValueRow>(provider.DatabaseContext); var mergedFieldValues = fieldValueCommand.OnConflict(row => row.FieldValueId) .Upsert(row => row.LastModifiedByDomainIdentifierId, row => row.LastModifiedTime) .Returning(row => row.FieldValueId, row => row.FieldId, row => row.LastModifiedByDomainIdentifierId, row => row.LastModifiedTime) .ExecuteForResults(fieldValues) .ToList(); Assert.IsTrue(mergedFieldValues.All(row => row.FieldValueId > 0)); // Map back to the domain object. foreach (var value in submission.SubmissionValues) { var input = mergedFieldValues.First(row => row.FieldId == value.Field.FieldId); this.mapper.MapTo(input, value); Assert.IsTrue(value.FieldValueId.HasValue); } // Now merge in the field value elements. // Do the field value elements var valueElements = (from e in submission.SubmissionValues.SelectMany(value => value.Elements) select new FieldValueElementPgFlatRow { FieldValueElementId = e.FieldValueElementId, FieldValueId = e.FieldValue.FieldValueId.GetValueOrDefault(), Order = e.Order, DateElement = e.Element as DateTimeOffset? ?? e.Element as DateTime?, FloatElement = e.Element as double? ?? e.Element as float?, IntegerElement = e.Element as long? ?? e.Element as int? ?? e.Element as short? ?? e.Element as byte?, MoneyElement = e.Element as decimal?, TextElement = e.Element as string // here we actually want it to be null if it is not a string }).ToList(); var elementMergeCommand = new JsonInsert <FieldValueElementRow>(provider.DatabaseContext); var mergedValueElements = elementMergeCommand.OnConflict(row => row.FieldValueElementId) .Upsert(row => row.Order) .Returning(row => row.FieldValueElementId, row => row.FieldValueId, row => row.Order) .ExecuteForResults(valueElements) .ToList(); foreach (var element in valueElements) { var input = mergedValueElements.First(row => row.FieldValueId == element.FieldValueId && row.Order == element.Order); this.mapper.MapTo(input, element); Assert.IsTrue(element.FieldValueElementId.HasValue); } var dateElementsCommand = new JsonInsert <DateElementRow>(provider.DatabaseContext) .From <FieldValueElementPgFlatRow>(row => row.FieldValueElementId, row => row.DateElement) .OnConflict(row => row.DateElementId) .Upsert(row => row.Value); dateElementsCommand.Execute(valueElements.Where(row => row.DateElement.HasValue)); var floatElementsCommand = new JsonInsert <FloatElementRow>(provider.DatabaseContext) .From <FieldValueElementPgFlatRow>(row => row.FieldValueElementId, row => row.FloatElement) .OnConflict(row => row.FloatElementId) .Upsert(row => row.Value); floatElementsCommand.Execute(valueElements.Where(row => row.FloatElement.HasValue)); var integerElementsCommand = new JsonInsert <IntegerElementRow>(provider.DatabaseContext) .From <FieldValueElementPgFlatRow>(row => row.FieldValueElementId, row => row.IntegerElement) .OnConflict(row => row.IntegerElementId) .Upsert(row => row.Value); integerElementsCommand.Execute(valueElements.Where(row => row.IntegerElement.HasValue)); var moneyElementsCommand = new JsonInsert <MoneyElementRow>(provider.DatabaseContext) .From <FieldValueElementPgFlatRow>(row => row.FieldValueElementId, row => row.MoneyElement) .OnConflict(row => row.MoneyElementId) .Upsert(row => row.Value); moneyElementsCommand.Execute(valueElements.Where(row => row.MoneyElement.HasValue)); var textElementsCommand = new JsonInsert <TextElementRow>(provider.DatabaseContext) .From <FieldValueElementPgFlatRow>(row => row.FieldValueElementId, row => row.TextElement) .OnConflict(row => row.TextElementId) .Upsert(row => row.Value); textElementsCommand.Execute(valueElements.Where(row => row.TextElement != null)); // Attach the values to the submission var genericValueSubmissions = from v in mergedFieldValues select new GenericSubmissionValueTableTypeRow { GenericSubmissionId = submission.GenericSubmissionId.GetValueOrDefault(), GenericSubmissionValueId = v.FieldValueId }; var submissionCommand = new JsonInsert <GenericSubmissionValueRow>(provider.DatabaseContext).Upsert( row => row.GenericSubmissionValueId, row => row.GenericSubmissionId); ////.DeleteUnmatchedInSource(row => row.GenericSubmissionId); Can't with PostgreSQL submissionCommand.Execute(genericValueSubmissions); transaction.Commit(); }