protected override void ExecuteLogic()
        {
            // get the triggering record
            var target = Target.ToEntity <NotificationMessage>();

            if (target.Regarding != null)
            {
                target.RegardingTypeCode = MetadataHelpers
                                           .GetEntityAttribute <int>(Service, target.Regarding.LogicalName,
                                                                     MetadataHelpers.EntityAttribute.ObjectTypeCode, Context.OrganizationId);
            }
        }
        public string GetIdFieldName(string logicalName)
        {
            var key = $"MetaDataHelper.GetIdFieldName|{logicalName}";
            var cachedEntityMetaData = GetFromMemCache <string>(key);

            if (cachedEntityMetaData != null)
            {
                return(cachedEntityMetaData);
            }

            var idFieldName = MetadataHelpers
                              .GetEntityAttribute <string>(service,
                                                           logicalName, MetadataHelpers.EntityAttribute.PrimaryIdAttribute, CrmService.OrgId);

            return(AddToMemCache(key, idFieldName));
        }
        public IEnumerable <string> GetAlternateKeys(string logicalName)
        {
            var key = $"MetaDataHelper.GetAlternateKeys|{logicalName}";
            var cachedEntityMetaData = GetFromMemCache <IEnumerable <string> >(key);

            if (cachedEntityMetaData != null)
            {
                return(cachedEntityMetaData);
            }

            var retrievedMetaData = MetadataHelpers
                                    .GetEntityAttribute <EntityKeyMetadata[]>(service,
                                                                              logicalName, MetadataHelpers.EntityAttribute.Keys, CrmService.OrgId);

            return(AddToMemCache(key, retrievedMetaData?.SelectMany(m => m.KeyAttributes ?? new string[0])));
        }
Exemple #4
0
        private IEnumerable <EntityReference> GetFilteredRecords(string logicalName,
                                                                 IEnumerable <ExportedEntityDefinition> recordDefinitions, RecordsFilterMode mode)
        {
            log.Log($"Getting filtered records ...");

            var uniqueRecords = new List <EntityReference>();

            log.Log($"Getting existing records for '{logicalName}'...");

            log.Log($"Getting ID field name ...");
            var idField = MetadataHelpers
                          .GetEntityAttribute <string>(service, logicalName, MetadataHelpers.EntityAttribute.PrimaryIdAttribute,
                                                       CrmService.OrgId);

            log.Log($"ID field name: {idField}.");

            log.Log($"Getting alternate key names ...");
            var alternateKeys = metadataHelper.GetAlternateKeys(logicalName).ToArray();

            log.Log($"Found {alternateKeys.Length} keys.");

            var definitions             = recordDefinitions.ToArray();
            var idDefinitions           = definitions.Where(d => !d.IsUseAlternateKeys || !d.Record.KeyAttributes.Any()).ToArray();
            var alternateKeyDefinitions = definitions.Where(d => d.IsUseAlternateKeys && d.Record.KeyAttributes.Any()).ToArray();

            Parallel.ForEach(idDefinitions.GroupBy(d => d.QueryKey),
                             new ParallelOptions
            {
                MaxDegreeOfParallelism = CrmService.Threads
            },
                             group =>
            {
                queries.TryGetValue(group.Key, out var fetchXml);
                fetchXml = BuildExistingRecordsFetchXml(fetchXml, idField);

                foreach (var relationKey in group.GroupBy(g => g.RelationId, g => g).Select(g => g.Key))
                {
                    var updatedFetchXml = UpdateRelatedConditionInFetchXml(fetchXml, relationKey);
                    var existingRecords = RetrieveRecords(updatedFetchXml);

                    switch (mode)
                    {
                    case RecordsFilterMode.UniqueInDestination:
                        uniqueRecords.AddRange(existingRecords.Select(r => r.Id).Except(group.Select(d => d.Record.Id))
                                               .Select(id => new EntityReference(logicalName, id)));
                        break;

                    case RecordsFilterMode.UniqueInSource:
                        uniqueRecords.AddRange(group.Select(d => d.Record.Id).Except(existingRecords.Select(r => r.Id))
                                               .Select(id => new EntityReference(logicalName, id)));
                        break;

                    case RecordsFilterMode.Common:
                        uniqueRecords.AddRange(group.Select(d => d.Record.Id).Intersect(existingRecords.Select(r => r.Id))
                                               .Select(id => new EntityReference(logicalName, id)));
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(mode), mode, "Unique records mode is out of range.");
                    }
                }
            });

            Parallel.ForEach(alternateKeyDefinitions.GroupBy(d => d.QueryKey),
                             new ParallelOptions
            {
                MaxDegreeOfParallelism = CrmService.Threads
            },
                             group =>
            {
                queries.TryGetValue(group.Key, out var fetchXml);
                fetchXml = BuildExistingRecordsFetchXml(fetchXml, idField, alternateKeys);

                foreach (var relationKey in group.GroupBy(g => g.RelationId, g => g).Select(g => g.Key))
                {
                    var updatedFetchXml = UpdateRelatedConditionInFetchXml(fetchXml, relationKey);
                    var existingRecords = RetrieveRecords(updatedFetchXml);

                    var exportedRecords = group.Select(d => d.Record);
                    IEnumerable <Guid> existingExceptExportedIds;

                    switch (mode)
                    {
                    case RecordsFilterMode.UniqueInDestination:
                        existingExceptExportedIds = existingRecords
                                                    .Where(r => exportedRecords.All(e => alternateKeys.All(
                                                                                        a =>
                        {
                            var firstValue  = r.GetAttributeValue <object>(a);
                            var secondValue = e.GetAttributeValue <object>(a);

                            return((firstValue != null && secondValue != null && !firstValue.Equals(secondValue)) ||
                                   (firstValue != secondValue));
                        })))
                                                    .Select(r => r.Id);
                        break;

                    case RecordsFilterMode.UniqueInSource:
                        existingExceptExportedIds = exportedRecords
                                                    .Where(r => existingRecords.All(e => alternateKeys.All(
                                                                                        a =>
                        {
                            var firstValue  = r.GetAttributeValue <object>(a);
                            var secondValue = e.GetAttributeValue <object>(a);

                            return((firstValue != null && secondValue != null && !firstValue.Equals(secondValue)) ||
                                   (firstValue != secondValue));
                        })))
                                                    .Select(r => r.Id);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(mode), mode, "Unique records mode is out of range.");
                    }

                    uniqueRecords.AddRange(existingExceptExportedIds
                                           .Select(id => new EntityReference(logicalName, id)));
                }
            });

            log.Log($"Got existing records for '{logicalName}'. Count: {uniqueRecords.Count}");

            return(uniqueRecords);
        }