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.");
        }
Example #2
0
        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);
        }
Example #3
0
        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;
                    }
                }
            }
        }
Example #4
0
        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);
        }