QueryExpression を使用して結果をページングする
ページ サイズを設定することで、リクエストごとに取得される行数の制限を指定できます。 ページングを使用すると、クエリの基準に一致するすべてのレコードを表すデータの連続ページを効率的な方法で取得できます。
既定の最大ページサイズは 5,000 行です。 ページサイズを設定しない場合、Dataverse は一度に 5,000 行までのデータを返します。 さらに多くの行を取得するには、追加のリクエストを送信する必要があります。
注意
- ページングでは、 QueryExpression.TopCount プロパティ を使用しないでください。 クエリの結果を制限するこれらのさまざまな方法には互換性がありません。
- 順序付けは、一貫したページング結果を得る上で重要な役割を果たします。 ご注文とページングについて
ページング モデル
Dataverse にが 2 つのページング モデルがあります: 単純 と ページング Cookie:
シンプル
- QueryExpression.PageInfo Count および PageNumber プロパティのみを使用します
- 小規模なデータセットのみに適しています
- 50,000 レコードを超えるデータ セットを返すことはできません
- 行数が増えるとパフォーマンスが低下する
ページング Cookie
- QueryExpression.PageInfo、Count、PageNumber、および PagingCookie プロパティを使用します。
PagingCookie
は、最初のリクエストでは null です。 後続の要求では、PagingCookie
プロパティを前のページによって返される値に設定します- すべてのデータセット サイズに推奨
- 一部のクエリではページング Cookie が許可されていません
- ページング Cookieの使用に関する詳細情報
シンプルなページング
リクエストを送信する前に、QueryExpression.PageInfo プロパティ を PagingInfo クラス インスタンスの PagingInfo.PageNumber を 1、 PagingInfo.Count にページ サイズを設定することで、最初のページをリクエストできます。
var query = new QueryExpression(entityName: "account")
{
ColumnSet = new ColumnSet("name"),
PageInfo = new PagingInfo() {
Count = 3,
PageNumber = 1
}
};
query.AddOrder(attributeName:"name",orderType: OrderType.Ascending);
query.AddOrder(attributeName: "accountid", orderType: OrderType.Ascending);
次の 3 つのレコードを取得するには、PageInfo.PageNumber
値を指定して別のリクエストを送信します。
query.PageInfo.PageNumber++;
レガシー ページング と呼ばれることもある単純なページングでは、Dataverse は現在のページまでのクエリの結果をすべて取得し、そのページに必要な数のレコードを選択し、残りは無視します。 これにより、データを素早く前後にページ移動したり、特定のページにスキップしたりすることができます。 ただし、レコードの合計数は 50,000 に制限されており、複雑なクエリや任意に並べ替えられた個別のクエリ結果に対してパフォーマンスの問題が発生する可能性があります。
単純なページングは小さいデータ セットにはうまく機能しますが、データ セット内の行数が増加すると、パフォーマンスが低下します。 あらゆるケースで最高のパフォーマンスを得るには、ページング Cookie を一貫して使用することをお勧めします。
ページング Cookie
最初のページをリクエストした後に、さらに取得すべき行がある場合、Dataverse通常 は、次のページのリクエストで使われるページング Cookie を返します。
ページング クッキーには、結果の最初のレコードと最後のレコードに関するデータが含まれており、Dataverse が次の行のデータをできるだけ早く取得するのに役立ちます。 前のページから戻った場合は、ページング クッキーを使用する必要があります。 ページング クッキー内のデータは変更せず、QueryExpression.PageInfo.PagingCookie プロパティに値を設定し、後続のリクエストの QueryExpression.PageInfo.PageNumber
値を増やしてください。
ページング Cookie をサポートしないクエリ
一部のクエリはページング cookie をサポートしていません。 ページング Cookie がクエリでサポートされていない場合、結果としてページング Cookie 値は返されません。 たとえば、LinkEntity
列を使用してソートされたクエリは、ページング クッキーをサポートしない可能性があります。
Dataverse がページング Cookie を返さない場合、ページング モデルは、それに付随するすべての制限を伴う単純なページングに戻ります。
ページング cookie 例
次の RetrieveAll
静的メソッドでは、 QueryExpression クエリに一致するすべてのレコードを返します。レコード数がページ サイズを超える場合は、複数のリクエストを送信します。
各リクエストの後、メソッドは EntityCollection.MoreRecords プロパティ をチェックして、条件に一致するレコードがさらにあるかどうかを判断します。 さらにレコードがある場合、メソッドは返された EntityCollection.PagingCookie プロパティ の値を PageInfo.PagingCookie
の QueryExpression
プロパティに設定し、別のリクエストを送信します。
/// <summary>
/// Returns all records matching the criteria
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance.</param>
/// <param name="query">The QueryExpression query</param>
/// <param name="page">The page size to use. Defaults to 5000</param>
/// <returns>All the records that match the criteria</returns>
static EntityCollection RetrieveAll(IOrganizationService service,
QueryExpression query,
int page = 5000)
{
// The records to return
List<Entity> entities = new();
// Set the page
query.PageInfo.PageNumber = 1;
// Set the count
query.PageInfo.Count = page;
while (true)
{
// Get the records
EntityCollection results = service.RetrieveMultiple(query);
entities.AddRange(results.Entities);
if (!results.MoreRecords)
{
//Stop if there are no more records
break;
}
// Set the PagingCookie with the PagingCookie from the previous query
query.PageInfo.PagingCookie = results.PagingCookie;
// Update the PageNumber
query.PageInfo.PageNumber++;
}
return new EntityCollection(entities);
}
次の手順で、クイック スタート: SDK for .NETリクエスト (C#) の実行 サンプルを調整して、QueryExpression
クエリをテストできます。
Program
クラスにRetrieveAll
静的メソッドを追加します。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);
QueryExpression query = new("contact")
{
ColumnSet = new ColumnSet("fullname", "jobtitle", "annualincome"),
Orders = {
{
new OrderExpression(
attributeName: "fullname",
orderType: OrderType.Descending)
}
}
};
EntityCollection records = RetrieveAll(service: serviceClient,
query: query)
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
一意の識別子を持つ列を含めることができない場合は、一意の組み合わせになる可能性が最も高い複数のフィールドを含めます。 例:
- 名 + 姓 + メールアドレス
- 姓名 + メールアドレス
- メールアドレス + 会社名
データをページングする際の注文のアンチパターン
避けるべき順序の選択肢は次のとおりです:
一意識別子を含まない並び順
計算フィールドの注文
次のような一意性を提供する可能性が低い単一または複数のフィールドを持つ並び順:
- 状態と進捗状況
- 選択肢または、はい/いいえ
- 値自体に名前を付けます。 例:
name
、firstname
、lastname
。 - タイトル、説明、複数行テキストなどのテキスト フィールド
- 一意でない数値フィールド
次の手順
データ集計の方法について解説します。
注意
ドキュメントの言語設定についてお聞かせください。 簡単な調査を行います。 (この調査は英語です)
この調査には約 7 分かかります。 個人データは収集されません (プライバシー ステートメント)。