예제 #1
0
        /// <summary>
        /// Performs an iterative series of RetrieveMultiple requests using FetchExpression in order to obtain all pages of results up to the provided maximum result count
        /// </summary>
        /// <param name="service">The current IOrganizationService instance</param>
        /// <param name="fetch">The FetchExpression query to be executed</param>
        /// <param name="shouldRetrieveAllPages">True = perform iterative paged query requests, otherwise return first page only</param>
        /// <param name="maxResultCount">An upper limit on the maximum number of entity records that should be retrieved as the query results - useful when the total size of result set is unknown and size may cause OutOfMemoryException</param>
        /// <param name="pagedOperation">An operation to perform on each page of results as it's retrieved</param>
        /// <returns>An EntityCollection containing the results of the query. Details reflect the last page retrieved (e.g. MoreRecords, PagingCookie, etc.)</returns>
        /// <remarks>
        /// CRM limits query response to paged result sets of 5,000. This method encapsulates the logic for performing subsequent
        /// query requests so that all results can be retrieved.
        /// </remarks>
        private static EntityCollection RetrieveMultiple(this IOrganizationService service, FetchExpression fetch, bool shouldRetrieveAllPages, long maxResultCount, Action <EntityCollection> pagedOperation)
        {
            XElement fetchXml   = fetch.ToXml();
            int      pageNumber = fetchXml.GetFetchXmlPageNumber();
            string   pageCookie = fetchXml.GetFetchXmlPageCookie();
            int      pageSize   = fetchXml.GetFetchXmlPageSize(QueryExtensions.DefaultPageSize);

            // Establish the first page based on lesser of initial/default page size or max result count (will be skipped if top count > 0)
            if (pageSize > maxResultCount)
            {
                pageSize = Convert.ToInt32(maxResultCount);
            }

            if (pageNumber <= 1 ||
                String.IsNullOrWhiteSpace(pageCookie))
            {
                // Ensure start with first page
                fetchXml.SetFetchXmlPage(null, 1, pageSize);
            }
            else
            {
                // Start with specified page
                fetchXml.SetFetchXmlPage(pageCookie, pageNumber, pageSize);
            }

            fetch.Query = fetchXml.ToString();

            // Track local long value to avoid expensive IEnumerable<T>.LongCount() method calls
            long totalResultCount = 0;
            var  allResults       = new EntityCollection();

            while (true)
            {
                // Retrieve the page
                EntityCollection page = service.RetrieveMultiple(fetch);

                // Capture the page
                if (totalResultCount == 0)
                {
                    // First page
                    allResults = page;
                }
                else
                {
                    allResults.Entities.AddRange(page.Entities);
                }

                // Invoke the paged operation if non-null
                pagedOperation?.Invoke(page);

                // Update the count of pages retrieved and processed
                totalResultCount = totalResultCount + page.Entities.Count;

                // Determine if we should retrieve the next page
                if (shouldRetrieveAllPages &&
                    totalResultCount < maxResultCount &&
                    page.MoreRecords)
                {
                    // Setup for next page
                    pageNumber++;

                    long remainder = maxResultCount - totalResultCount;

                    // If max result count is not divisible by page size, then final page may be less than the current page size and should be sized to remainder.
                    // No risk of coversion overflow.
                    if (pageSize > remainder)
                    {
                        pageSize = Convert.ToInt32(remainder);
                    }

                    fetch.SetPage(page.PagingCookie, pageNumber, pageSize);
                }
                else
                {
                    allResults.CopyFrom(page);
                    break;
                }
            }

            return(allResults);
        }
예제 #2
0
        /// <summary>
        /// Performs an iterative series of RetrieveMultiple requests using QueryExpression in order to obtain all pages of results up to the provided maximum result count
        /// </summary>
        /// <param name="service">The current IOrganizationService instance</param>
        /// <param name="query">The QueryExpression query to be executed</param>
        /// <param name="shouldRetrieveAllPages">True = perform iterative paged query requests, otherwise return first page only</param>
        /// <param name="maxResultCount">An upper limit on the maximum number of entity records that should be retrieved as the query results - useful when the total size of result set is unknown and size may cause OutOfMemoryException</param>
        /// <param name="pagedOperation">An operation to perform on each page of results as it's retrieved</param>
        /// <returns>An EntityCollection containing the results of the query. Details reflect the last page retrieved (e.g. MoreRecords, PagingCookie, etc.)</returns>
        /// <remarks>
        /// CRM limits query response to paged result sets of 5,000. This method encapsulates the logic for performing subsequent
        /// query requests so that all results can be retrieved.
        /// </remarks>
        private static EntityCollection RetrieveMultiple(this IOrganizationService service, QueryExpression query, bool shouldRetrieveAllPages, long maxResultCount, Action <EntityCollection> pagedOperation)
        {
            // Establish page info (only if TopCount not specified)
            if (query.TopCount == null)
            {
                if (query.PageInfo == null)
                {
                    // Default to first page
                    query.PageInfo = new PagingInfo()
                    {
                        Count                  = QueryExtensions.DefaultPageSize,
                        PageNumber             = 1,
                        PagingCookie           = null,
                        ReturnTotalRecordCount = false
                    };
                }
                else if (query.PageInfo.PageNumber <= 1 ||
                         query.PageInfo.PagingCookie == null)
                {
                    // Reset to first page
                    query.PageInfo.PageNumber   = 1;
                    query.PageInfo.PagingCookie = null;
                }

                // Limit initial page size to max result if less than current page size. No risk of conversion overflow.
                if (query.PageInfo.Count > maxResultCount)
                {
                    query.PageInfo.Count = Convert.ToInt32(maxResultCount);
                }
            }

            // Track local long value to avoid expensive IEnumerable<T>.LongCount() method calls
            long totalResultCount = 0;
            var  allResults       = new EntityCollection();

            while (true)
            {
                // Retrieve the page
                EntityCollection page = service.RetrieveMultiple(query);

                // Capture the page
                if (totalResultCount == 0)
                {
                    // First page
                    allResults = page;
                }
                else
                {
                    allResults.Entities.AddRange(page.Entities);
                }

                // Invoke the paged operation if non-null
                pagedOperation?.Invoke(page);

                // Update the count of pages retrieved and processed
                totalResultCount = totalResultCount + page.Entities.Count;

                // Determine if we should retrieve the next page
                if (shouldRetrieveAllPages &&
                    totalResultCount < maxResultCount &&
                    page.MoreRecords)
                {
                    // Setup for next page
                    query.PageInfo.PageNumber++;
                    query.PageInfo.PagingCookie = page.PagingCookie;

                    long remainder = maxResultCount - totalResultCount;

                    // If max result count is not divisible by page size, then final page may be less than the current page size and should be sized to remainder.
                    // No risk of coversion overflow.
                    if (query.PageInfo.Count > remainder)
                    {
                        query.PageInfo.Count = Convert.ToInt32(remainder);
                    }
                }
                else
                {
                    allResults.CopyFrom(page);
                    break;
                }
            }

            return(allResults);
        }