FetchXml を使用したページ結果

ページ サイズを設定することで、リクエストごとに取得される行数の制限を指定できます。 ページングを使用すると、クエリの基準に一致するすべてのレコードを表すデータの連続ページを効率的な方法で取得できます。

既定の最大ページサイズは 5,000 行です。 ページサイズを設定しない場合、Dataverse は一度に 5,000 行までのデータを返します。 さらに多くの行を取得するには、追加のリクエストを送信する必要があります。

注意

  • ページングでは 要素の取り込み top 属性を使用しないでください。 クエリの結果を制限するこれらのさまざまな方法には互換性がありません。
  • 順序付けは、一貫したページング結果を得る上で重要な役割を果たします。 ご注文とページングについて

ページング モデル

Dataverse にが 2 つのページング モデルがあります: 単純ページング Cookie:

シンプル

  • 取り込み要素 countpage 属性のみを使用します
  • 小規模なデータセットのみに適しています
  • 50,000 レコードを超えるデータ セットを返すことはできません
  • 行数が増えるとパフォーマンスが低下する

ページング Cookie

シンプルなページング

リクエストを送信する前に、取り込み要素 page 属性を 1 に、count 属性をページ サイズに設定することで、最初のページにリクエストすることができます:

<fetch count='3' page='1'>
  <entity name='account'>
    <attribute name='name' />
    <order attribute='name' />
    <order attribute='accountid' />
  </entity>
</fetch>

次の 3 つのレコードを取得するには、page 値を指定して別のリクエストを送信します。

<fetch count='3' page='2'>
  <entity name='account'>
    <attribute name='name' />
    <order attribute='name' />
    <order attribute='accountid' />    
  </entity>
</fetch>

レガシー ページング と呼ばれることもある単純なページングでは、Dataverse は現在のページまでのクエリの結果をすべて取得し、そのページに必要な数のレコードを選択し、残りは無視します。 これにより、データを素早く前後にページ移動したり、特定のページにスキップしたりすることができます。 ただし、レコードの合計数は 50,000 に制限されており、複雑なクエリや任意に並べ替えられた個別のクエリ結果に対してパフォーマンスの問題が発生する可能性があります。

単純なページングは​​小さいデータ セットにはうまく機能しますが、データ セット内の行数が増加すると、パフォーマンスが低下します。 単純なページングを使用して取得できる行の合計数は 50,000 です。 あらゆるケースで最高のパフォーマンスを得るには、ページング Cookie を一貫して使用することをお勧めします。

ページング Cookie

最初のページをリクエストした後に、さらに取得すべき行がある場合、Dataverse通常 は、次のページのリクエストで使われるページング Cookie を返します。

ページング Cookie には、結果の最初と最後のレコードに関するデータが含まれており、Dataverse データの次の行をできるだけ早く取得するため、指定された場合には使用する必要があります。 ページング Cookie 内のデータを修正すべきではありません。取り込み要素paging-cookie 属性に値を設定し、後続のリクエストのために page 属性の値をインクリメントするだけです。

ページング Cookie をサポートしないクエリ

一部のクエリはページング cookie をサポートしていません。 ページング Cookie がクエリでサポートされていない場合、結果としてページング Cookie 値は返されません。 たとえば、クエリを使用して並べ替えると、link-entity 属性はページング Cookie をサポートしていない可能性があります。

Dataverse がページング Cookie を返さない場合、ページング モデルは、それに付随するすべての制限を伴う単純なページングに戻ります。

ページング cookie をどのように使用するかは、SDK for .NET または Web API のどちらを使用しているかによって異なります。

次の RetrieveAll 静的メソッドは、FetchXml クエリに一致するすべてのレコードを返し、レコード数がページ サイズを超える場合は複数のリクエストを送信します。

各リクエストの後、メソッドは EntityCollection.MoreRecords プロパティ をチェックして、条件に一致するレコードがさらにあるかどうかを判断します。 さらにレコードがある場合、メソッドは返された EntityCollection.PagingCookie プロパティ の値を 取り込み要素paging-cookie 属性に設定し、別のリクエストを送信します。

/// <summary>
/// Returns all records matching the criteria
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance.</param>
/// <param name="fetchXml">The fetchXml Query string</param>
/// <param name="pageSize">The page size to use. Default is 5000</param>
/// <returns>All the records that match the criteria</returns>
static EntityCollection RetrieveAll(IOrganizationService service, string fetchXml, int pageSize = 5000)
{

    // The records to return
    List<Entity> entities = new();

    XElement fetchNode = XElement.Parse(fetchXml);

    int page = 1; //Start with page 1

    //Set the page
    fetchNode.SetAttributeValue("page", page);

    // Set the page size
    fetchNode.SetAttributeValue("count", pageSize);

    while (true)
    {
        // Get the page
        EntityCollection results = service.RetrieveMultiple(new FetchExpression(fetchNode.ToString()));

        entities.AddRange(results.Entities);

        if (!results.MoreRecords)
        {
            break;
        }

        // Set the fetch paging-cookie attribute with the paging cookie from the previous query
        fetchNode.SetAttributeValue("paging-cookie", results.PagingCookie);

        fetchNode.SetAttributeValue("page", ++page);
    }
    return new EntityCollection(entities);
}

次の手順で、クイック スタート: SDK for .NETリクエスト (C#) の実行 サンプルを調整して、FetchXml クエリをテストできます。

  1. Program クラスに RetrieveAll 静的メソッドを追加します。
  2. Main メソッドを以下のように変更します:
static void Main(string[] args)
{
    using (ServiceClient serviceClient = new(connectionString))
    {
        if (serviceClient.IsReady)
        {
            //WhoAmIResponse response = 
            //    (WhoAmIResponse)serviceClient.Execute(new WhoAmIRequest());

            //Console.WriteLine("User ID is {0}.", response.UserId);

            string fetchQuery = @"<fetch count='3' page='1'>
                <entity name='contact'>
                    <attribute name='fullname'/>
                    <attribute name='jobtitle'/>
                    <attribute name='annualincome'/>
                    <order descending='true' attribute='fullname'/>
                </entity>
        </fetch>";

            EntityCollection records = RetrieveAll(service: serviceClient,
                        fetchXml: fetchQuery,
                        pageSize: 25);

            Console.WriteLine($"Success: {records.Entities.Count}");
        }
        else
        {
            Console.WriteLine(
                "A web service connection was not established.");
        }
    }

    // Pause the console so it does not close.
    Console.WriteLine("Press the <Enter> key to exit.");
    Console.ReadLine();
}

重要

このクエリは、条件に一致するすべてのレコードを返します。 結果を制限するには、フィルター要素を必ず含めてください。

ページングと並び順

ページの順序は、データをページングする際に大きな違いをもたらします。 結果の順序に関する情報があいまいな場合、Dataverse はページングされたデータを一貫して効率的に返すことができません。

クエリの順序を指定します。 FetchXml では、クエリに順序要素を追加しない場合、Dataverse がテーブルの主キーに基づいて順序を追加します。 ただし、QueryExpression の場合は異なり、クエリで distinct 結果を指定すると、主キー値が返されないため、Dataverse はこの既定の順序を追加することはできません。 ページングの順序を指定してください。 順序を指定しないと、distinct クエリの結果がランダムな順序で返される可能性があります。 OData では個別の結果を返すオプションは提供されていませんが、ページ化された結果を取得するときには順序を適用する必要があります。

ページングは動的です。 各リクエストは受信時に独立して評価されます。 ページング Cookie は Dataverse に前のページを伝えます。 このページング Cookie データを使用すると、Dataverse は前のページの最後のレコードの次のレコードから開始できます。

ページングは​​今後も最適に機能します。 以前に取得したページに戻って取得すると、最後にページを取得してからの間にレコードが追加、削除、または変更されている可能性があるため、結果が異なる可能性があります。 つまり、ページ サイズが 50 で前に戻ると、50 レコードが取得されますが、それらは同じ 50 レコードではない可能性があります。 データ セットのページを進め続けると、すべてのレコードが一貫した順序で返されることが期待できます。

決定論的な順序付けが重要となります

決定的順序付け とは、順序を一貫して計算する方法があることを意味します。 指定されたレコードのセットでは、レコードは常に同じ順序で返されます。 一貫した順序とページングが必要な場合は、一意の値または列値の組み合わせをいくつか含め、それらが評価される順序を指定する必要があります。

非決定的な例

ここで nondeterministic のサンプルを見てみましょう。 このデータセットには 状態ステータス の情報のみが含まれ、オープン 状態 のレコードのみを返すようにフィルターされています。 結果は、ステータス によって次のように並べ替えられます。 最初の 3 ページが要求されます。 結果はこのようになります:

状態 Status ぺージ
アクティブです 1 スタート
アクティブです 1
アクティブです 1 終了
アクティブです
アクティブです
非アクティブ
非アクティブ

ページング Cookie は、ページ上の最後のレコードに関する情報を保存します。 次のページが要求された場合、最初のページの最後のレコードは含まれません。 ただし、非決定的なデータを考えると、最初のページの他の 2 つのレコードが 2 番目のページに含まれていないという保証はありません。

決定的な順序付けを実現するには、一意の値または半一意の値を含む列に順序を追加します。

決定的な例

このクエリは非決定的なクエリと似ていますが、一意な値を含むケース ID 列を含んでいます。 ステータス順でもありますが、ケース ID の使用用途順でもあります。 結果はこのようになります:

状態 Status サポート案件 ID ぺージ
アクティブです Case-0010 1 スタート
アクティブです Case-0021 1
アクティブです Case-0032 1 終了
アクティブです Case-0034
アクティブです Case-0070
非アクティブ Case-0015
非アクティブ Case-0047

次のページでは、cookie は最初のページの最後のレコードとして Case-0032 を保存しているので、2 ページ目はそのレコードの次のレコードから始まります。 結果はこのようになります:

状態 Status サポート案件 ID ぺージ
アクティブです Case-0010 1 スタート
アクティブです Case-0021 1
アクティブです Case-0032 1 終了
アクティブです Case-0034 2 スタート
アクティブです Case-0070 2
非アクティブ Case-0015 2 終了
非アクティブ Case-0047

このクエリは一意の列値を順序付けするため、順序は一貫しています。

データをページングするときの注文のベスト プラクティス

注意

可能な場合、クエリはテーブルの主キーに基づいて順序付けされる必要があります。 Dataverse は、既定で主キーの順序付けに最適化されています。 一意でないフィールドまたは複雑なフィールドで順序付けすると、過剰なオーバーヘッドが発生し、クエリが遅くなります。

アプリケーションで表示するために限られたデータセットを取得する場合、または 5,000 行以上のデータを返す必要がある場合は、結果をページングする必要があります。 結果の順序を決定する際の選択によって、取得するデータの各ページの行が他のページと重なるかどうかが決まります。 適切に順序付けしない場合、同じレコードが複数のページに表示される可能性があります。

同じレコードが複数のページに表示されないようにするには、次のベスト プラクティスを適用します:

一意の識別子を持つ列を含めることをお勧めします。 例:

  • テーブルの主キー列
  • オートナンバー列
  • ユーザー/連絡先 ID

一意の識別子を持つ列を含めることができない場合は、一意の組み合わせになる可能性が最も高い複数のフィールドを含めます。 例:

  • 名 + 姓 + メールアドレス
  • 姓名 + メールアドレス
  • メールアドレス + 会社名

データをページングする際の注文のアンチパターン

避けるべき順序の選択肢は次のとおりです:

  • 一意識別子を含まない並び順

  • 計算フィールドの注文

  • 次のような一意性を提供する可能性が低い単一または複数のフィールドを持つ並び順:

    • 状態と進捗状況
    • 選択肢または、はい/いいえ
    • 値自体に名前を付けます。 例: namefirstnamelastname
    • タイトル、説明、複数行テキストなどのテキスト フィールド
    • 一意でない数値フィールド

次の手順

データ集計の方法について解説します。

注意

ドキュメントの言語設定についてお聞かせください。 簡単な調査を行います。 (この調査は英語です)

この調査には約 7 分かかります。 個人データは収集されません (プライバシー ステートメント)。