public IEnumerable <CrmEntityIndexDocument> GetDocuments()
        {
            ADXTrace.Instance.TraceInfo(TraceCategory.Application, "Start");

            var dataContext     = _index.DataContext;
            var documentFactory = new FetchXmlIndexDocumentFactory(_index, _fetchXml, _titleAttributeLogicalName, _localeConfig);

            var currentPageFetchXml    = _fetchXml;
            var knowledgeArticleFilter = new FetchXmlResultsFilter();

            while (true)
            {
                var request = new OrganizationRequest("ExecuteFetch");
                request.Parameters["FetchXml"] = currentPageFetchXml.ToString();

                var response = dataContext.Execute(request);

                if (response == null)
                {
                    throw new InvalidOperationException("Did not receive valid response from ExecuteFetchRequest.");
                }

                var fetchXmlResponse = response.Results["FetchXmlResult"] as string;

                if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.CmsEnabledSearching))
                {
                    if (this._fetchXml.LogicalName == "knowledgearticle")
                    {
                        fetchXmlResponse = knowledgeArticleFilter.Aggregate(fetchXmlResponse, "knowledgearticleid", "record2id.productid",
                                                                            "adx_contentaccesslevelid.adx_contentaccesslevelid", "record2id.connectionid", "annotation.filename",
                                                                            "annotation.notetext", "annotation.annotationid");
                    }
                    if (this._fetchXml.LogicalName == "annotation")
                    {
                        fetchXmlResponse = knowledgeArticleFilter.Aggregate(fetchXmlResponse, "annotationid", "product.productid");
                    }
                }

                var resultSet = new FetchXmlResultSet(fetchXmlResponse);

                ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("FetchXmlResult:LogicalName={0}, Count={1}", EntityNamePrivacy.GetEntityName(this._fetchXml.LogicalName), resultSet.Count()));

                foreach (var document in resultSet.Select(documentFactory.GetDocument))
                {
                    yield return(document);
                }

                if (resultSet.MoreRecords)
                {
                    currentPageFetchXml = currentPageFetchXml.ForNextPage(resultSet.PagingCookie);
                }
                else
                {
                    break;
                }
            }

            ADXTrace.Instance.TraceInfo(TraceCategory.Application, "End");
        }
        /// <summary>
        /// Receives entire Fetch Xml and aggregates duplicate results caused by having N:N or 1:N relationships.
        /// </summary>
        /// <param name="fetchXml">The fetch XML.</param>
        /// <param name="primaryKeyFieldName">Entity Id field name</param>
        /// <param name="fields">List of fields</param>
        /// <returns>Aggregated results on Fetch Xml</returns>
        public string Aggregate(string fetchXml, string primaryKeyFieldName, params string[] fields)
        {
            var fetchXmlParsed = XDocument.Parse(fetchXml);
            var inputResults   = fetchXmlParsed.Descendants("result").ToList();

            if (inputResults.Count == 0)
            {
                return(fetchXml);
            }

            var aggregatedResults = new Dictionary <string, XElement>();
            var parsedResultSet   = new FetchXmlResultSet(fetchXml);

            bool isFirstPage = this.lastResultOnPage == null;
            bool isLastPage  = !parsedResultSet.MoreRecords;

            //// Check if last result of last page and first result of this page are the same article.
            //// If not, we need to add the aggregated result from last page during this round.
            //// If so, the past CAL/product ids should still be stored and we'll just add to
            if (!isFirstPage)
            {
                var firstId            = inputResults.First().Descendants(primaryKeyFieldName).FirstOrDefault().Value;
                var previousPageLastId = this.lastResultOnPage.Descendants(primaryKeyFieldName).FirstOrDefault().Value;
                if (firstId != previousPageLastId)
                {
                    aggregatedResults[previousPageLastId] = this.lastResultOnPage;
                }
            }
            var lastId = inputResults.Descendants(primaryKeyFieldName).FirstOrDefault().Value;

            var collectionOfFields = fields.Select(fieldName => new RelatedField(fieldName)).ToList();

            //// Iterating through fetchXml retrieving multiple related fields
            foreach (var resultNode in inputResults)
            {
                var primaryKeyFieldNode = resultNode.Descendants(primaryKeyFieldName).FirstOrDefault();
                if (primaryKeyFieldNode == null)
                {
                    return(fetchXml);
                }

                ////Retrieving fields
                collectionOfFields.ForEach(field => this.GetRelatedFields(resultNode, field, primaryKeyFieldNode.Value));
                ////Removing duplicate nodes
                aggregatedResults[primaryKeyFieldNode.Value] = resultNode;
            }

            var node = inputResults.FirstOrDefault();

            if (node == null)
            {
                return(fetchXml);
            }
            var parentNode = node.Parent;

            if (parentNode == null)
            {
                return(fetchXml);
            }

            fetchXmlParsed.Descendants("result").Remove();

            //// Inserting retrieved above related fields and deduplicated results.
            collectionOfFields.ForEach(field => this.InsertRelatedFields(aggregatedResults, field));

            //// Remove and store the last aggregated result, as this might be the same article as the first result on the
            //// next page.
            this.lastResultOnPage = aggregatedResults[lastId];
            if (!isLastPage)
            {
                aggregatedResults.Remove(lastId);
            }

            fetchXmlParsed.Element(parentNode.Name).Add(aggregatedResults.Values);
            return(fetchXmlParsed.ToString());
        }