private void VerifyKeysInFetchXml(Record recordsConfig) { log.Log($"Verifying keys exist in record ..."); log.Log($"Retrieving keys for {recordsConfig.LogicalName} ..."); var keys = metadataHelper.GetAlternateKeys(recordsConfig.LogicalName)?.ToArray(); log.Log( $"Finished retrieving keys for {recordsConfig.LogicalName}. Keys: {keys?.Aggregate((e1, e2) => $"{e1},{e2}")}"); if (keys == null) { log.LogWarning($"Can't find alterate keys definition for entity: '{recordsConfig.LogicalName}'."); return; } foreach (var key in keys) { if (!Regex.IsMatch(recordsConfig.FetchXml, $"<attribute\\s*name\\s*=\\s*(\"|'){key}(\"|')") && Regex.IsMatch(recordsConfig.FetchXml, $"<attribute\\s*name\\s*=\\s*(\"|').*(\"|')")) { throw new Exception($"Can't find alterate key '{key}' in FetchXML of entity {recordsConfig.LogicalName}."); } } log.Log($"Finished verifying keys exist in record."); }
private static AutoNumbering GetBackloggedConfig(IPluginExecutionContext currentContext, IOrganizationService service, CrmLog log) { var xrmContext = new XrmServiceContext(service) { MergeOption = MergeOption.NoTracking }; var triggerIdGuid = GetTriggerId(currentContext); // check backlog if necessary if (triggerIdGuid == null) { log.Log("No trigger ID found."); return(null); } var triggerId = triggerIdGuid.ToString(); log.Log($"Found trigger ID '{triggerId}' in shared variables."); log.Log("Retrieving backlog entry ..."); var triggerBacklog = (from backlogQ in xrmContext.AutoNumberingBacklogSet join autonumberQ in xrmContext.AutoNumberingSet on backlogQ.AutoNumberingConfig equals autonumberQ.AutoNumberingId where backlogQ.TriggerID == triggerId select new AutoNumberingBacklog { Id = backlogQ.Id, IndexValue = backlogQ.IndexValue, AutoNumberingConfig = backlogQ.AutoNumberingConfig, AutoNumberingAsAutoNumberingConfig = autonumberQ }).FirstOrDefault(); log.Log("Finished retrieving backlog entry."); if (triggerBacklog == null) { log.LogWarning($"Couldn't find backlog entry for trigger ID '{triggerId}'."); return(null); } log.Log($"Using backlog '{triggerBacklog.Id}' with index {triggerBacklog.IndexValue}."); triggerBacklog.AutoNumberingAsAutoNumberingConfig.CurrentIndex = triggerBacklog.IndexValue; log.Log("Deleting backlog entry ..."); service.Delete(triggerBacklog.LogicalName, triggerBacklog.Id); log.Log("Finished deleting backlog entry."); return(triggerBacklog.AutoNumberingAsAutoNumberingConfig); }
private static void ImportSolutions(IEnumerable <string> connectionStrings, IReadOnlyCollection <ExportedSolution> importSolutions, Dictionary <string, List <ExportedSolution> > failures) { connectionStrings.Require("DestinationConnectionStrings"); importSolutions.Require(nameof(importSolutions)); failures.Require(nameof(failures)); if (!importSolutions.Any()) { log.LogWarning("No solution to import."); return; } foreach (var connectionString in connectionStrings) { var failedSolutionList = new List <ExportedSolution>(); try { log.Log($"Importing solutions into '{EscapePassword(connectionString)}' ..."); using (var destinationService = ConnectToCrm(connectionString)) { foreach (var solution in importSolutions) { try { log.Log($"Processing solution '{solution.SolutionName}' ..."); if (IsSolutionUpdated(solution.SolutionName, solution.Version, destinationService)) { var isImported = ImportSolution(solution, destinationService); if (!isImported) { failedSolutionList.Add(solution); } } else { log.Log("Identical solution versions. Skipping ..."); } } catch (Exception e) { log.Log(e); failedSolutionList.Add(solution); } finally { log.Log($"Finished processing solution '{solution.SolutionName}'."); } } } } catch (Exception e) { log.Log(e); failedSolutionList.AddRange(importSolutions); } finally { if (failedSolutionList.Any()) { failures[connectionString] = failedSolutionList; } } } }
public bool ImportRecords(string rawData) { var splitRawData = rawData.Split(new[] { "<|||>" }, StringSplitOptions.RemoveEmptyEntries); if (!splitRawData.Any()) { throw new Exception("Data given is empty."); } var rawStringData = splitRawData[0]; if (splitRawData.Length > 1 && splitRawData[1] == "TRUE") { data = Helpers.Helpers.Decompress <ExportedData>(rawStringData); if (splitRawData.Length > 2) { options = ImportOptions.FromJson(splitRawData[2]); } } else { data = Helpers.Helpers.Deserialise <ExportedData>(Encoding.UTF8.GetBytes(rawStringData)); } if (data?.EntityDefinition == null) { log.LogWarning("Import data is empty, skipping ..."); return(true); } log.Log($"Importing {data.EntityDefinition?.Count} records."); log.Log($"Importing {data.RelationDefinition?.Count} relations."); Initialise(); ProcessObsoleteRecordsRemoval(); var dependencyRequests = ProcessDependencies(recordsMap.Values.ToArray()).ToList(); var requests = GetSyncRequests(); idsMap = requests .ToDictionary(e => GetIdFromRequestResponse(e) ?? Guid.Empty, e => GetIdFromRequestResponse(e) ?? Guid.Empty); foreach (var key in recordsMap.Keys.Except(idsMap.Keys)) { idsMap[key] = key; } idsMap[Guid.Empty] = Guid.Empty; var keyedRecords = recordsMap .Where(e => e.Value.IsUseAlternateKeys && e.Value.Record.KeyAttributes.Any()) .Select(e => e.Value.Record).ToArray(); log.Log($"Clearing IDs of ${keyedRecords.Length} keyed records ..."); foreach (var record in keyedRecords) { record.Id = Guid.Empty; } var responses = ExecuteRequests(requests, "Failed in record sync step."); MapOldIdsToNewIds(requests, responses.Values); UpdateRelationRequestIds(); ProcessObsoleteRelationsRemoval(); UpdateLookupRequestIds(dependencyRequests); ExecuteRequests(dependencyRequests.Cast <OrganizationRequest>().ToList(), "Failed in lookup dependencies update step."); var associateRequests = CreateAssociateRequests().ToArray(); ExecuteRequests(associateRequests.Cast <OrganizationRequest>().ToList(), "Failed in association step.", faultMessage => faultMessage != null && !faultMessage.Contains("Cannot insert duplicate key")); return(true); }