Morning Girl

Web API, Windows, C#, .NET, Dynamics 365/CRM etc..

【C#】【Dynamics CRM】QueryExpression によるページングの指定

Dynamics CRM から組織サービス経由で大量のデータを取得(RetrieveMultiple)する場合、標準で取得件数5000件制限が付与されています。

予めフィルターしたデータを取得するのであれば、あまり問題にはなりませんが、 5000件を超えるデータを取得することが予想される場合、何かした対応をしておかないといけません。

対応方法

対応方法としては以下のものが考えられます。

  1. Filter条件でTop、Underを指定し、データ取得を回す。
  2. RetrieveMultipleのQueryにページングの設定をして、データ取得を回す。
  3. Dynamics CRM オンプレミスのレジストリを弄って、取得上限件数を上げる。

手法としては【1.】でも可能ですが、Dynamics CRM ではページングという機能が推奨されている感じなので【2.】がいいと思います。

【3.】は最終手段的な感じですが、要件次第では……。という感じでしょうか。

参考URL

The number of search results that is returned is 5,000 when you set the "Count" attribute to 20,000 in Microsoft Dynamics CRM

PageInfoクラス

QueryExpressionクラスのPageInfoプロパティを設定することで利用可能です。

PagingInfo のメンバー

PagingInfo のメンバー (Microsoft.Xrm.Sdk.Query)

重要なメンバーは下記3つ ・Count ・PageNumber ・PagingCookie

【Count】は一度のRetrieveMultipleで取得してくるレコードの件数(1ページにおける件数)を指定します。 これはどちらにしても最大5000件までしか指定できません。

【PageNumber】は取得してくるデータセットの番号になっており、ここを繰り上げることで、Countで指定した件数を繰り上げて取得していくことができます。 今回Countは"5000"なので、1ページ目は1~5000、2ページ目は5001~10000、といった形で取得してくることになります。

【PagingCookie】は一度取得してきたデータの最初と最後のGUIDを明示的に指定しているXMLです。 PageNumberの繰り上げとともに、PagingCookieを指定することで、続くデータの取得が可能になります。 (と書いておいて、PageNumberだけじゃ、ダメなのか? という疑問が湧いてきたけど)

コード

今回のコードでは、通常のQueryExpressionとページングを利用したQueryExpressionとでメソッドを分けてみました。

using System;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;

namespace MyProject.CrmGetAllRecord
{
    class Program
    {
        static void Main(string[] args)
        {
            var connection = CrmConnection.Parse("Url=https://***.crm7.dynamics.com; Username=***@***.onmicrosoft.com; Password=***;");
            var service = new OrganizationService(connection);

            Console.WriteLine("Start Get All Entity Collection");

            EntityCollection collection1 = GetAllEntityCollection("account",service);

            EntityCollection collection2 = GetAllEntityCollectionNomal("account", service);

            Console.WriteLine("Get Collection Data. Set Page Info Properties : {0}", collection1.Entities.Count);

            Console.WriteLine("Get Collection Data. Nomal Type : {0}", collection2.Entities.Count);

            Console.ReadKey();
        }

        /// <summary>
        /// QueryExpression により通常取得
        /// </summary>
        /// <param name="EntityName"></param>
        /// <param name="service"></param>
        /// <returns></returns>
        private static EntityCollection GetAllEntityCollectionNomal( string EntityName,OrganizationService service)
        {
            QueryExpression query = new QueryExpression();

            query.EntityName = EntityName;
            query.ColumnSet.AddColumn(EntityName + "id");

            return service.RetrieveMultiple(query);
        }

        /// <summary>
        /// QueryExpressionでPageに関するparameterを設定
        /// </summary>
        /// <param name="EntityName"></param>
        /// <param name="service"></param>
        /// <returns></returns>
        private static EntityCollection GetAllEntityCollection(string EntityName, OrganizationService service)
        {
            QueryExpression query = new QueryExpression();

            query.EntityName = EntityName;
            query.ColumnSet.AddColumn(EntityName + "id");

            query.PageInfo = new PagingInfo()
            {
                Count = 5000,
                PageNumber = 1,
                PagingCookie = null
            };

            EntityCollection returnCollection = new EntityCollection();

            // MoreRecords が Falseになるまで、PageNumberを増やしてRetrieveMultipleし続ける。
            while (true)
            {
                EntityCollection results = service.RetrieveMultiple(query);

                if (results.Entities != null)
                {
                    returnCollection.Entities.AddRange(results.Entities);
                }

                if (results.MoreRecords)
                {
                    query.PageInfo.PageNumber++;
                    query.PageInfo.PagingCookie = results.PagingCookie;
                }
                else
                {
                    break;
                }
            }

            return returnCollection;
        }
    }
}

結果画面

f:id:sugimomoto:20150406154545p:plain

参考URL

QueryExpression を使用して大きな結果セットをページングする