public object Clone()
        {
            var clone = new ImportProgress(Count);

            foreach (var entity in Entities)
            {
                clone.Entities.Add((EntityProgress)entity.Clone());
            }

            return(clone);
        }
Esempio n. 2
0
        // helper function to track the progress of the current list of records being imported
        private EntityProgress GetEntityProgress(List <Entity> coll, Entity record, ImportProgress progress, List <EntityMetadata> emds)
        {
            // get the entity progress for this record entity type.
            var entityProgress = progress.Entities.FirstOrDefault(e => e.LogicalName == record.LogicalName);

            if (entityProgress == null)
            {
                var emd = emds.FirstOrDefault(e => e.LogicalName == record.LogicalName);
                if (emd == null)
                {
                    PortalMover.ReportProgress($"Record: Entity Logical Name: {record.LogicalName} for ID: {record.Id} not found in the target instance metadata.");
                    return(null);
                }
                string displayName = emd.DisplayName?.UserLocalizedLabel?.Label;

                if (displayName == null && emd.IsIntersect.Value)
                {
                    var rel = emds.SelectMany(ent => ent.ManyToManyRelationships)
                              .First(r => r.IntersectEntityName == emd.LogicalName);
                    var nameOne = emds.FirstOrDefault(ent => ent.LogicalName == rel.Entity1LogicalName)?.DisplayName?.UserLocalizedLabel?.Label;
                    var nameTwo = emds.FirstOrDefault(ent => ent.LogicalName == rel.Entity2LogicalName)?.DisplayName?.UserLocalizedLabel?.Label;
                    displayName = $"{nameOne } / {nameTwo}";
                }
                if (displayName == null)
                {
                    displayName = emd.SchemaName;
                }

                entityProgress = new EntityProgress(emd, displayName)
                {
                    Count = coll.Count(r => r.LogicalName == record.LogicalName)
                };
                progress.Entities.Add(entityProgress);
            }
            return(entityProgress);
        }
Esempio n. 3
0
        public bool ProcessRecords(EntityCollection ec, List <EntityMetadata> emds, int organizationMajorVersion = 9)
        {
            var records = new List <Entity>(ec.Entities);

            // Move annotation at the beginning if the list as the list will be
            // inverted to allow list removal. This way, annotation are
            // processed as the last records
            var annotations = records.Where(e => e.LogicalName == "annotation").ToList();

            records = records.Except(annotations).ToList();
            records.InsertRange(0, annotations);

            var progress = new ImportProgress(records.Count);

            var nextCycle = new List <Entity>();

            // reset Error state for each
            progress.Entities.ForEach(p => { p.ErrorFirstPhase = 0; });

            for (int i = records.Count - 1; i >= 0; i--)
            {
                EntityProgress entityProgress;

                var record = records[i];

                // Handle annotations.
                if (record.LogicalName != "annotation")
                {
                    // see if any records in the entity collection have a reference to this Annotation
                    if (record.Attributes.Values.Any(v =>
                                                     v is EntityReference reference &&
                                                     records.Select(r => r.Id).Contains(reference.Id)
                                                     ))
                    {
                        if (nextCycle.Any(r => r.Id == record.Id))
                        {
                            continue;
                        }

                        var newRecord = new Entity(record.LogicalName)
                        {
                            Id = record.Id
                        };
                        var toRemove = new List <string>();
                        foreach (var attr in record.Attributes)
                        {
                            if (attr.Value is EntityReference)
                            {
                                newRecord.Attributes.Add(attr.Key, attr.Value);
                                toRemove.Add(attr.Key);
                                nextCycle.Add(newRecord);
                            }
                        }

                        foreach (var attr in toRemove)
                        {
                            record.Attributes.Remove(attr);
                        }
                    }

                    if (record.Attributes.Values.Any(v =>
                                                     v is Guid guid &&
                                                     records.Where(r => r.Id != record.Id)
                                                     .Select(r => r.Id)
                                                     .Contains(guid)
                                                     ))
                    {
                        nextCycle.Add(record);
                        records.RemoveAt(i);
                        continue;
                    }
                }
                // check for entity progress.. entity may not be in target system
                entityProgress = GetEntityProgress(records, record, progress, emds);
                if (entityProgress == null)
                {
                    continue;
                }
                try
                {
                    record.Attributes.Remove("ownerid");

                    if (record.Attributes.Contains("statecode") &&
                        record.GetAttributeValue <OptionSetValue>("statecode").Value == 1)
                    {
                        PortalMover.ReportProgress($"Import: Record {record.GetAttributeValue<string>(entityProgress.Metadata.PrimaryNameAttribute)} is inactive : Added for deactivation step");

                        recordsToDeactivate.Add(record.ToEntityReference());
                        record.Attributes.Remove("statecode");
                        record.Attributes.Remove("statuscode");
                    }

                    if (organizationMajorVersion >= 8)
                    {
                        var result = (UpsertResponse)service.Execute(new UpsertRequest
                        {
                            Target = record
                        });

                        PortalMover.ReportProgress($"Import: Record {record.GetAttributeValue<string>(entityProgress.Metadata.PrimaryNameAttribute)} {(result.RecordCreated ? "created" : "updated")} ({entityProgress.Entity}/{record.Id})");
                    }
                    else
                    {
                        bool exists = false;
                        try
                        {
                            service.Retrieve(record.LogicalName, record.Id, new ColumnSet());
                            exists = true;
                        }
                        catch
                        {
                            // Do nothing
                        }

                        if (exists)
                        {
                            service.Update(record);
                            PortalMover.ReportProgress($"Import: Record {record.GetAttributeValue<string>(entityProgress.Metadata.PrimaryNameAttribute)} updated ({entityProgress.Entity}/{record.Id})");
                        }
                        else
                        {
                            service.Create(record);
                            PortalMover.ReportProgress($"Import: Record {record.GetAttributeValue<string>(entityProgress.Metadata.PrimaryNameAttribute)} created ({entityProgress.Entity}/{record.Id})");
                        }
                    }

                    if (record.LogicalName == "annotation" && settings.Config.CleanWebFiles)
                    {
                        var reference = record.GetAttributeValue <EntityReference>("objectid");
                        if (reference?.LogicalName == "adx_webfile")
                        {
                            PortalMover.ReportProgress($"Import: Searching for extra annotation in web file {reference.Id:B}");

                            var qe = new QueryExpression("annotation")
                            {
                                NoLock   = true,
                                Criteria = new FilterExpression
                                {
                                    Conditions =
                                    {
                                        new ConditionExpression("annotationid", ConditionOperator.NotEqual,
                                                                record.Id),
                                        new ConditionExpression("objectid",     ConditionOperator.Equal,
                                                                reference.Id),
                                    }
                                }
                            };

                            var extraNotes = service.RetrieveMultiple(qe);
                            foreach (var extraNote in extraNotes.Entities)
                            {
                                PortalMover.ReportProgress($"Import: Deleting extra note {extraNote.Id:B}");
                                service.Delete(extraNote.LogicalName, extraNote.Id);
                            }
                        }
                    }

                    records.RemoveAt(i);
                    entityProgress.SuccessFirstPhase++;
                }
                catch (Exception error)
                {
                    PortalMover.ReportProgress($"Import: {record.GetAttributeValue<string>(entityProgress.Metadata.PrimaryNameAttribute)} ({entityProgress.Entity}/{record.Id}): {error.Message}");
                    entityProgress.ErrorFirstPhase++;
                }
                finally
                {
                    entityProgress.Processed++;
                }
            }

            PortalMover.ReportProgress($"Import: Updating records to add references and processing many-to-many relationships...");

            var count = nextCycle.DistinctBy(r => r.Id).Count();
            var index = 0;

            foreach (var record in nextCycle.DistinctBy(r => r.Id))
            {
                var entityProgress = GetEntityProgress(nextCycle, record, progress, emds);

                if (!entityProgress.SuccessSecondPhase.HasValue)
                {
                    entityProgress.SuccessSecondPhase = 0;
                    entityProgress.ErrorSecondPhase   = 0;
                }

                try
                {
                    index++;

                    PortalMover.ReportProgress($"Import: Upating record {record.LogicalName} ({record.Id})");

                    record.Attributes.Remove("ownerid");

                    if (record.Attributes.Count == 3 && record.Attributes.Values.All(v => v is Guid))
                    {
                        PortalMover.ReportProgress($"Import: Creating association {entityProgress.Entity} ({record.Id})");

                        try
                        {
                            var rel =
                                emds.SelectMany(e => e.ManyToManyRelationships)
                                .First(r => r.IntersectEntityName == record.LogicalName);

                            service.Associate(rel.Entity1LogicalName,
                                              record.GetAttributeValue <Guid>(rel.Entity1IntersectAttribute),
                                              new Relationship(rel.SchemaName),
                                              new EntityReferenceCollection(new List <EntityReference>
                            {
                                new EntityReference(rel.Entity2LogicalName,
                                                    record.GetAttributeValue <Guid>(rel.Entity2IntersectAttribute))
                            }));

                            PortalMover.ReportProgress($"Import: Association {entityProgress.Entity} ({record.Id}) created");
                        }
                        catch (FaultException <OrganizationServiceFault> error)
                        {
                            if (error.Detail.ErrorCode != -2147220937)
                            {
                                throw;
                            }

                            PortalMover.ReportProgress($"Import: Association {entityProgress.Entity} ({record.Id}) already exists");
                        }
                        finally
                        {
                            entityProgress.Processed++;
                        }
                    }
                    else
                    {
                        service.Update(record);
                    }
                }
                catch (Exception error)
                {
                    PortalMover.ReportProgress($"Import: An error occured during import: {error.Message}");
                    entityProgress.ErrorSecondPhase = entityProgress.ErrorSecondPhase.Value + 1;
                }
            }

            #region Deactivate Records
            if (recordsToDeactivate.Any())
            {
                count = recordsToDeactivate.Count;
                index = 0;

                PortalMover.ReportProgress($"Import: Deactivating records...");

                foreach (var er in recordsToDeactivate)
                {
                    var entityProgress = progress.Entities.First(e => e.LogicalName == er.LogicalName);
                    if (!entityProgress.SuccessSecondPhase.HasValue)
                    {
                        entityProgress.SuccessSetStatePhase = 0;
                        entityProgress.ErrorSetState        = 0;
                    }

                    try
                    {
                        index++;

                        PortalMover.ReportProgress($"Import: Deactivating record {er.LogicalName} ({er.Id})");

                        var recordToUpdate = new Entity(er.LogicalName)
                        {
                            Id             = er.Id,
                            ["statecode"]  = new OptionSetValue(1),
                            ["statuscode"] = new OptionSetValue(-1)
                        };

                        service.Update(recordToUpdate);

                        var percentage = index * 100 / count;
                        entityProgress.SuccessSetStatePhase++;
                    }
                    catch (Exception error)
                    {
                        var percentage = index * 100 / count;
                        entityProgress.ErrorSetState++;
                    }
                }
            }
            #endregion

            return(false);
        }
        public bool ProcessRecords(EntityCollection ec, List <EntityMetadata> emds)
        {
            var records  = new List <Entity>(ec.Entities);
            var progress = new ImportProgress(records.Count);

            var nextCycle = new List <Entity>();
            int loopIndex = 0;

            while (records.Any())
            {
                loopIndex++;
                if (loopIndex == maxErrorLoopCount)
                {
                    break;
                }

                for (int i = records.Count - 1; i >= 0; i--)
                {
                    EntityProgress entityProgress;

                    var record = records[i];
                    // Handle annotations.
                    // TODO review this section
                    if (record.LogicalName != "annotation")
                    {
                        // see if any records in the entity collection have a reference to this Annotation
                        if (record.Attributes.Values.Any(v => v is EntityReference && records.Select(r => r.Id).Contains(((EntityReference)v).Id)))
                        {
                            if (nextCycle.Any(r => r.Id == record.Id))
                            {
                                continue;
                            }

                            var newRecord = new Entity(record.LogicalName)
                            {
                                Id = record.Id
                            };
                            var toRemove = new List <string>();
                            foreach (var attr in record.Attributes)
                            {
                                if (attr.Value is EntityReference)
                                {
                                    newRecord.Attributes.Add(attr.Key, attr.Value);
                                    toRemove.Add(attr.Key);
                                    nextCycle.Add(newRecord);
                                }
                            }

                            foreach (var attr in toRemove)
                            {
                                record.Attributes.Remove(attr);
                            }
                        }
                        //
                        if (record.Attributes.Values.Any(v => (v is Guid) && records.Where(r => r.Id != record.Id).Select(r => r.Id).Contains((Guid)v)))
                        {
                            continue;
                        }
                    }

                    // update the entity progress element
                    TrackEntityProgress();

                    try
                    {
                        record.Attributes.Remove("ownerid");

                        // check to see if this is an N:N relation vs a standard record import.
                        if (record.Attributes.Count == 3 && record.Attributes.Values.All(v => v is Guid))
                        {
                            try
                            {
                                // perform the association!
                                var rel = emds.SelectMany(e => e.ManyToManyRelationships).First(r => r.IntersectEntityName == record.LogicalName);

                                service.Associate(
                                    rel.Entity1LogicalName,
                                    record.GetAttributeValue <Guid>(rel.Entity1IntersectAttribute),
                                    new Relationship(rel.SchemaName),
                                    new EntityReferenceCollection(new List <EntityReference>
                                {
                                    new EntityReference(rel.Entity2LogicalName, record.GetAttributeValue <Guid>(rel.Entity2IntersectAttribute))
                                })
                                    );

                                PortalMover.ReportProgress($"Import: Association {entityProgress.Entity} ({record.Id}) created");
                            }
                            catch (FaultException <OrganizationServiceFault> error)
                            {
                                if (error.Detail.ErrorCode != -2147220937)
                                {
                                    throw;
                                }
                                PortalMover.ReportProgress($"Import: Association {entityProgress.Entity} ({record.Id}) already exists");
                            }
                        }
                        else
                        {
                            // Do the Insert/Update!
                            var result = (UpsertResponse)service.Execute(new UpsertRequest {
                                Target = record
                            });
                            PortalMover.ReportProgress($"Import: Record {record.GetAttributeValue<string>(entityProgress.Metadata.PrimaryNameAttribute)} {(result.RecordCreated ? "created" : "updated")} ({entityProgress.Entity}/{record.Id})");
                        }

                        records.RemoveAt(i);
                        entityProgress.Success++;
                        entityProgress.Processed++;
                    }
                    catch (Exception error)
                    {
                        PortalMover.ReportProgress($"Import: An error occured attempting the insert/update/associate: {record.GetAttributeValue<string>(entityProgress.Metadata.PrimaryNameAttribute)} ({entityProgress.Entity}/{record.Id}): {error.Message}");
                        entityProgress.Error++;
                    }

                    // track the progress of the current list of records being imported
                    void TrackEntityProgress()
                    {
                        // get the entity progress for this record entity type.
                        entityProgress = progress.Entities.FirstOrDefault(e => e.LogicalName == record.LogicalName);
                        if (entityProgress == null)
                        {
                            var    emd         = emds.First(e => e.LogicalName == record.LogicalName);
                            string displayName = emd.DisplayName?.UserLocalizedLabel?.Label;

                            if (displayName == null && emd.IsIntersect.Value)
                            {
                                var rel = emds.SelectMany(ent => ent.ManyToManyRelationships)
                                          .First(r => r.IntersectEntityName == emd.LogicalName);

                                displayName = $"{emds.First(ent => ent.LogicalName == rel.Entity1LogicalName).DisplayName?.UserLocalizedLabel?.Label} / {emds.First(ent => ent.LogicalName == rel.Entity2LogicalName).DisplayName?.UserLocalizedLabel?.Label}";
                            }
                            if (displayName == null)
                            {
                                displayName = emd.SchemaName;
                            }

                            entityProgress = new EntityProgress(emd, displayName);
                            progress.Entities.Add(entityProgress);
                        }
                    }
                }
            }

            PortalMover.ReportProgress("Import: Updating records to add references");

            var count = nextCycle.DistinctBy(r => r.Id).Count();
            var index = 0;

            foreach (var record in nextCycle.DistinctBy(r => r.Id))
            {
                try
                {
                    index++;

                    PortalMover.ReportProgress($"Import: Upating record {record.LogicalName} ({record.Id})");

                    record.Attributes.Remove("ownerid");
                    service.Update(record);
                }
                catch (Exception error)
                {
                    PortalMover.ReportProgress($"Import: An error occured during import: {error.Message}");
                }
            }
            return(false);
        }