QueryExpression を使用して行の順序を決定する

テーブル内の行の並べ替え順序を指定するには、 QueryExpression.Orders または LinkEntity.Orders プロパティを使用します。

注意

Orders プロパティは読み取り専用です。 オブジェクトの初期化または QueryExpression.AddOrder 算出方法 を使って、OrderExpression インスタンスをこのコレクションに設定できます。

LinkEntity には、AddOrder 算出方法がありません。 Orders プロパティが継承する System.Collections.ObjectModel.Collection<T> 算出方法 を使用することもできます。

規定の並べ替え順序は、OrderType.Ascending です。

以下のクエリは、createdonnameaccountnumber の値の昇順で アカウント レコードを返します。

var query = new QueryExpression(entityName: "account") { 
    ColumnSet = new ColumnSet("name", "accountnumber", "createdon"),
    Orders = {
        { 
            new OrderExpression(
                attributeName: "createdon", 
                orderType: OrderType.Ascending) 
        },
        {
            new OrderExpression(
                attributeName: "name",
                orderType: OrderType.Ascending)
        },
        {
            new OrderExpression(
                attributeName: "accountnumber",
                orderType: OrderType.Ascending)
        },
    }
};

同じクエリは、QueryExpression.AddOrder 算出方法 を使用して作成できます。

var query = new QueryExpression(entityName: "account") { 
    ColumnSet = new ColumnSet("name", "accountnumber", "createdon")
};
query.AddOrder(attributeName: "createdon", orderType: OrderType.Ascending);
query.AddOrder(attributeName: "name", orderType: OrderType.Ascending);
query.AddOrder(attributeName: "accountnumber", orderType: OrderType.Ascending);

要素の順序によって、順序付けがどのように適用されるかが決まります。 accountnumber を使用して順序を適用するには、まずその順序を追加します。

query.AddOrder(attributeName: "accountnumber", orderType: OrderType.Ascending);
query.AddOrder(attributeName: "createdon", orderType: OrderType.Ascending);
query.AddOrder(attributeName: "name", orderType: OrderType.Ascending);

降順

降順 を使用する場合は、OrderType.Descending を使用します。 次の例では、最後に作成されたレコードが先頭にある取引先企業レコードを返します。

var query = new QueryExpression(entityName: "account") { 
    ColumnSet = new ColumnSet("name", "createdon")
};
query.AddOrder(attributeName: "createdon", orderType: OrderType.Descending);

LinkEntity 順序を最初に処理する

Dataverse は常に、LinkEntity.Orders で指定された列は、QueryExpression.Orders の後に順序付けられます。

次の例は、LinkEntity 列と QueryExpression 列の両方の従来の順序付けパターンを示しています。

var query = new QueryExpression(entityName: "account")
{
    ColumnSet = new ColumnSet("name", "accountnumber", "createdon"),
    LinkEntities = {
        new LinkEntity(
            linkFromEntityName:"account",
            linkToEntityName:"account",
            linkFromAttributeName: "parentaccountid",
            linkToAttributeName:"accountid",
            joinOperator: JoinOperator.Inner){
             EntityAlias = "parentaccount",
             Columns = new ColumnSet("name"),
             Orders = {
                {
                    new OrderExpression(
                        attributeName:"name",
                        orderType: OrderType.Ascending)
                }
            }
        }
    },
    Orders = {
                {
                    new OrderExpression(
                        attributeName:"name",
                        orderType: OrderType.Ascending)
                }
    }
};

この場合、結果は次の属性を使用して順序付けされます。

  • 最初 => account.name
  • 最後 => parentaccountname.name

LinkEntity 順序が最初に適用されるようにするには、OrderExpressionLinkEntity.Orders から QueryExpression.Orders 他の上 OrderExpressionに移動し、OrderExpression.EntityName を使用して LinkEntity.EntityAlias 値を参照します。

var query = new QueryExpression(entityName: "account")
{
    ColumnSet = new ColumnSet("name", "accountnumber", "createdon"),
    LinkEntities = {
        new LinkEntity(
            linkFromEntityName:"account",
            linkToEntityName:"account",
            linkFromAttributeName: "parentaccountid",
            linkToAttributeName:"accountid",
            joinOperator: JoinOperator.Inner){
             EntityAlias = "parentaccount",
             Columns = new ColumnSet("name")
        }
    },
    Orders = {
                {
                    new OrderExpression(
                        attributeName:"name",
                        orderType: OrderType.Ascending){
                        // LinkEntity.EntityAlias value
                        EntityName = "parentaccount"
                    }
                },
                {
                    new OrderExpression(
                        // QueryExpression Columns name
                        attributeName:"name",
                        orderType: OrderType.Ascending)
                }
    }
};

以上で、結果は次の属性を使用して順序付けされます。

  • 最初 => parentaccount.name
  • 最後 => account.name

ルックアップ列と選択列の順序付け

ほとんどの列タイプに含まれるデータは比較的単純なので、意味のある並べ替え操作を実行できます。 データベースに保存されているデータはコンテキストを離れては意味を持たないため、ルックアップ列と選択列はより複雑になります。

検索列

ルックアップ列を使用して並べ替えると、結果は関連テーブルのプライマリ名フィールドを使用して並べ替えられます。 データベースには GUID 値が格納されます。 返される フォーマットされた値 は、対応する主な名前フィールドです。

選択列

選択列の値も、データベースに保存されている値ではなく、 フォーマットされた値 を使用して並べ替えられます。 これらの列のデータは整数として保存されます。 フォーマットされた値は、ユーザーの言語に基づいてローカライズされたラベルです。

注意

選択肢の並べ替えはユーザーの言語のローカライズされたラベルに基づいているため、ユーザーの言語が異なる場合、結果セットの順序が異なることになります。

ページングと並び順

ページの順序は、データをページングする際に大きな違いをもたらします。 結果の順序に関する情報があいまいな場合、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
    • タイトル、説明、複数行テキストなどのテキスト フィールド
    • 一意でない数値フィールド

次の手順

行をフィルター処理する方法について説明します。