Exemple #1
0
        /// <inheritdoc/>
        protected override object ExecuteInternal(IOrganizationService org, IAttributeMetadataCache metadata, IQueryExecutionOptions options)
        {
            // Check if the query is allowed
            if (options.Cancelled)
            {
                return(null);
            }

            if (options.BlockDeleteWithoutWhere && !FetchXml.Items.OfType <FetchEntityType>().Single().Items.OfType <filter>().Any())
            {
                throw new InvalidOperationException("DELETE without WHERE is blocked by your settings");
            }

            var meta = metadata[EntityName];

            // If we are using a bulk delete job, start the job
            if (options.UseBulkDelete && Extensions.Count == 0 && meta.IsIntersect != true)
            {
                var query = ((FetchXmlToQueryExpressionResponse)org.Execute(new FetchXmlToQueryExpressionRequest {
                    FetchXml = Serialize(FetchXml)
                })).Query;

                var bulkDelete = new BulkDeleteRequest
                {
                    JobName               = $"SQL 4 CDS {meta.DisplayCollectionName.UserLocalizedLabel.Label} Bulk Delete Job",
                    QuerySet              = new[] { query },
                    StartDateTime         = DateTime.Now,
                    RunNow                = true,
                    RecurrencePattern     = String.Empty,
                    SendEmailNotification = false,
                    ToRecipients          = new Guid[0],
                    CCRecipients          = new Guid[0]
                };

                org.Execute(bulkDelete);

                return("Bulk delete job started");
            }

            // Otherwise, get the records to delete
            var count    = 0;
            var entities = RetrieveAll(org, metadata, options).Entities;

            if (entities == null)
            {
                return(null);
            }

            // Check again if the query is allowed
            if (!options.ConfirmDelete(entities.Count, meta))
            {
                throw new OperationCanceledException("DELETE cancelled by user");
            }

            ExecuteMultipleRequest multiple = null;

            // Delete hte records in batches
            foreach (var entity in entities)
            {
                if (options.Cancelled)
                {
                    break;
                }

                if (options.BatchSize == 1)
                {
                    options.Progress($"Deleting {meta.DisplayName.UserLocalizedLabel.Label} {count + 1:N0} of {entities.Count:N0}...");
                    org.Execute(CreateDeleteRequest(meta, entity));
                    count++;
                }
                else
                {
                    if (multiple == null)
                    {
                        multiple = new ExecuteMultipleRequest
                        {
                            Requests = new OrganizationRequestCollection(),
                            Settings = new ExecuteMultipleSettings
                            {
                                ContinueOnError = false,
                                ReturnResponses = false
                            }
                        };
                    }

                    multiple.Requests.Add(CreateDeleteRequest(meta, entity));

                    if (multiple.Requests.Count == options.BatchSize)
                    {
                        options.Progress($"Deleting {meta.DisplayCollectionName.UserLocalizedLabel.Label} {count + 1:N0} - {count + multiple.Requests.Count:N0} of {entities.Count:N0}...");
                        var resp = (ExecuteMultipleResponse)org.Execute(multiple);
                        if (resp.IsFaulted)
                        {
                            throw new ApplicationException($"Error deleting {meta.DisplayCollectionName.UserLocalizedLabel.Label}");
                        }

                        count += multiple.Requests.Count;

                        multiple = null;
                    }
                }
            }

            if (!options.Cancelled && multiple != null)
            {
                options.Progress($"Deleting {meta.DisplayCollectionName.UserLocalizedLabel.Label} {count + 1:N0} - {count + multiple.Requests.Count:N0}...");
                var resp = (ExecuteMultipleResponse)org.Execute(multiple);
                if (resp.IsFaulted)
                {
                    throw new ApplicationException($"Error deleting {meta.DisplayCollectionName.UserLocalizedLabel.Label}");
                }

                count += multiple.Requests.Count;
            }

            return($"{count:N0} {meta.DisplayCollectionName.UserLocalizedLabel.Label} deleted");
        }
Exemple #2
0
        public override string Execute(IDictionary <string, DataSource> dataSources, IQueryExecutionOptions options, IDictionary <string, Type> parameterTypes, IDictionary <string, object> parameterValues)
        {
            _executionCount++;

            try
            {
                if (!dataSources.TryGetValue(DataSource, out var dataSource))
                {
                    throw new QueryExecutionException("Missing datasource " + DataSource);
                }

                List <Entity>         entities;
                EntityMetadata        meta;
                Func <Entity, object> primaryIdAccessor;
                Func <Entity, object> secondaryIdAccessor = null;

                using (_timer.Run())
                {
                    entities = GetDmlSourceEntities(dataSources, options, parameterTypes, parameterValues, out var schema);

                    // Precompile mappings with type conversions
                    meta = dataSource.Metadata[LogicalName];
                    var    attributes   = meta.Attributes.ToDictionary(a => a.LogicalName);
                    var    dateTimeKind = options.UseLocalTimeZone ? DateTimeKind.Local : DateTimeKind.Utc;
                    var    primaryKey   = meta.PrimaryIdAttribute;
                    string secondaryKey = null;

                    // Special cases for the keys used for intersect entities
                    if (meta.LogicalName == "listmember")
                    {
                        primaryKey   = "listid";
                        secondaryKey = "entityid";
                    }
                    else if (meta.IsIntersect == true)
                    {
                        var relationship = meta.ManyToManyRelationships.Single();
                        primaryKey   = relationship.Entity1IntersectAttribute;
                        secondaryKey = relationship.Entity2IntersectAttribute;
                    }

                    var fullMappings = new Dictionary <string, string>
                    {
                        [primaryKey] = PrimaryIdSource
                    };

                    if (secondaryKey != null)
                    {
                        fullMappings[secondaryKey] = SecondaryIdSource;
                    }

                    var attributeAccessors = CompileColumnMappings(meta, fullMappings, schema, attributes, dateTimeKind);
                    primaryIdAccessor = attributeAccessors[primaryKey];

                    if (SecondaryIdSource != null)
                    {
                        secondaryIdAccessor = attributeAccessors[secondaryKey];
                    }
                }

                // Check again that the update is allowed. Don't count any UI interaction in the execution time
                if (options.Cancelled || !options.ConfirmDelete(entities.Count, meta))
                {
                    throw new OperationCanceledException("DELETE cancelled by user");
                }

                using (_timer.Run())
                {
                    return(ExecuteDmlOperation(
                               dataSource.Connection,
                               options,
                               entities,
                               meta,
                               entity => CreateDeleteRequest(meta, entity, primaryIdAccessor, secondaryIdAccessor),
                               new OperationNames
                    {
                        InProgressUppercase = "Deleting",
                        InProgressLowercase = "deleting",
                        CompletedLowercase = "deleted"
                    }));
                }
            }
            catch (QueryExecutionException ex)
            {
                if (ex.Node == null)
                {
                    ex.Node = this;
                }

                throw;
            }
            catch (Exception ex)
            {
                throw new QueryExecutionException(ex.Message, ex)
                      {
                          Node = this
                      };
            }
        }
Exemple #3
0
 public bool ConfirmDelete(int count, EntityMetadata meta)
 {
     return(_options.ConfirmDelete(count, meta));
 }