private XmlDocument CreateAttachmentDescriptionDoc(TfsMigrationFileAttachment f, string revision)
        {
            Debug.Assert(!string.IsNullOrEmpty(revision));

            XmlDocument migrationActionDetails = new XmlDocument();
            XmlElement  root = migrationActionDetails.CreateElement("WorkItemChanges");

            root.SetAttribute("WorkItemID", XmlConvert.ToString(WorkItem.Id));
            root.SetAttribute("Revision", revision);
            root.SetAttribute("WorkItemType", WorkItem.Type.Name);
            migrationActionDetails.AppendChild(root);

            XmlElement c = migrationActionDetails.CreateElement("Attachment");

            c.SetAttribute("Name", f.Name);
            c.SetAttribute("Length", XmlConvert.ToString(f.Length));
            c.SetAttribute("UtcCreationDate", XmlConvert.ToString(f.UtcCreationDate, XmlDateTimeSerializationMode.Unspecified));
            c.SetAttribute("UtcLastWriteDate", XmlConvert.ToString(f.UtcLastWriteDate, XmlDateTimeSerializationMode.Unspecified));
            XmlElement v = migrationActionDetails.CreateElement("Comment");

            v.InnerText = f.Comment;
            c.AppendChild(v);
            root.AppendChild(c);
            return(migrationActionDetails);
        }
        internal void ComputeAttachmentDelta(
            ChangeGroupService changeGroupService,
            DateTime waterMarkChangeStartTime,
            ITranslationService translationService,
            Guid sourceId,
            List <ChangeGroup> groups)
        {
            List <TfsMigrationFileAttachment> files = new List <TfsMigrationFileAttachment>();

            if (WorkItem.Attachments.Count > 0)
            {
                List <Revision> revsToBeSynced = FindUnsyncedRevisions(waterMarkChangeStartTime,
                                                                       translationService,
                                                                       sourceId,
                                                                       null);

                bool hasAttachmentChanges = false;
                foreach (Revision rev in revsToBeSynced)
                {
                    if (rev.Index == 0 &&
                        (int)rev.Fields[CoreField.AttachedFileCount].Value > 0)
                    {
                        hasAttachmentChanges = true;
                        break;
                    }

                    if (rev.Index > 0)
                    {
                        int      currAttchCount = (int)rev.Fields[CoreField.AttachedFileCount].Value;
                        Revision prevRev        = rev.WorkItem.Revisions[rev.Index - 1];
                        int      prevAttchCount = (int)prevRev.Fields[CoreField.AttachedFileCount].Value;
                        if (currAttchCount != prevAttchCount)
                        {
                            hasAttachmentChanges = true;
                            break;
                        }
                    }
                }

                if (!hasAttachmentChanges)
                {
                    return;
                }

                foreach (Attachment attachment in WorkItem.Attachments)
                {
                    if (attachment.AttachedTimeUtc <= waterMarkChangeStartTime ||
                        !attachment.IsSaved)
                    {
                        continue;
                    }
                    files.Add(new TfsMigrationFileAttachment(attachment));
                }
            }

            Guid        changeActionId = WellKnownChangeActionId.AddAttachment;
            ChangeGroup changeGroup    = changeGroupService.CreateChangeGroupForDeltaTable(
                string.Format("{0}:{1}", WorkItem.Id, "Attachments"));

            foreach (TfsMigrationFileAttachment attachmentFile in files)
            {
                XmlDocument migrationActionDetails = CreateAttachmentDescriptionDoc(attachmentFile, WorkItem.Rev.ToString());
                changeGroup.CreateAction(
                    changeActionId,
                    attachmentFile,
                    WorkItem.Id.ToString(),
                    "",
                    "0",
                    "",
                    WellKnownContentType.WorkItem.ReferenceName,
                    migrationActionDetails);
            }

            // VERY IMPORTANT: use the RelatedArtifactsStore to detect detailed attachment changes
            WorkItemAttachmentStore       store = new WorkItemAttachmentStore(sourceId);
            List <FileAttachmentMetadata> additionalAttachmentToDelete;

            store.UpdatePerItemAttachmentChangesByCheckingRelatedItemRecords(
                WorkItem.Id.ToString(), changeGroup, out additionalAttachmentToDelete);

            foreach (FileAttachmentMetadata attch in additionalAttachmentToDelete)
            {
                TfsMigrationFileAttachment attachmentFile = new TfsMigrationFileAttachment(attch);
                XmlDocument migrationActionDetails        = CreateAttachmentDescriptionDoc(attachmentFile, WorkItem.Rev.ToString());
                changeGroup.CreateAction(
                    WellKnownChangeActionId.DelAttachment,
                    attachmentFile,
                    WorkItem.Id.ToString(),
                    "",
                    "0",
                    "",
                    WellKnownContentType.WorkItem.ReferenceName,
                    migrationActionDetails);
            }

            groups.Add(changeGroup);
        }