次の方法で共有


QueryExpression を使用して列を選択する

重要

クエリでテーブル内のすべての列を返すことは強くお勧めしません。 すべての列を返すと、アプリケーションの実行が遅くなり、タイムアウト エラーが発生する可能性があります。 データとともに取得する列の最小数を指定する必要があります。 ColumnSet.AllColumns プロパティ を true に設定すると、すべての列のデータが返されます。 列を設定しない場合は、レコードの主キー値のみが返されます。 これは、FetchXml を使用した場合の動作とは逆で、何も指定しない場合はすべての列が返されます

クエリで返される列の名前を指定するには、ColumnSet クラス を使用します。 各列に AttributeMetadata.LogicalName 値を使用します。 論理名の値は常に小文字になります。

QueryExpression を初期化するときに、ColumnSet(String[]) コンストラクター を使用して列を指定できます。

QueryExpression query = new("account")
{
    ColumnSet = new ColumnSet("name", "accountclassificationcode", "createdby", "createdon")
};

また、ColumnSet.AddColumn または ColumnSet.AddColumns メソッドを使用して、 QueryExpression.ColumnSet プロパティ が初期化された後に、QueryExpression に追加の列を追加できます。

QueryExpression query = new("account");
query.ColumnSet.AddColumn("name");
query.ColumnSet.AddColumns("accountclassificationcode", "createdby", "createdon");

注意

一部の列は読み取りについて有効ではありません。 AttributeMetadata.IsValidForRead プロパティ は、列が読み取りに有効かどうかを示します。 これらの列の名前を含めると、値は返されません。

ColumnSet.Columns プロパティ は、System.Collections.ObjectModel.Collection<T>クラス を拡張する Microsoft.Xrm.Sdk.DataCollection<文字列> であるため、これらの基本クラスのメソッドを使用してコレクション内の文字列を操作することもできます。

結合テーブルの列を選択する

QueryExpression を使用してテーブルを結合する場合、LinkEntity クラスを使用します。 LinkEntity.Columns プロパティColumnSet なので、結合されたテーブルに対して返される列を同じ方法で定義します。

早期バインド フィール ドクラス

pac modelbuilder コマンドemitfieldsclasses スイッチを有効にして使用して生成された早期バインド フィールド クラスを使用している場合、論理名を文字列として直接使用するのではなく、生成された定数をすべてのフィールド名に使用できます。

QueryExpression query = new(Account.EntityLogicalName)
{
   ColumnSet = new ColumnSet(
      Account.Fields.Name, 
      Account.Fields.AccountClassificationCode,
      Account.Fields.CreatedBy, 
      Account.Fields.CreatedOn)
};

これにより、間違った名前を入力することによる実行時エラーを回避できます。 詳細情報

列の別名

列エイリアスは通常、 集計操作に使用されますが、行の取得にも役立つため、ここで紹介します。

返される結果の一意の列名を指定するには、XrmAttributeExpression インスタンスを ColumnSet.AttributeExpressions コレクションに追加します。 各インスタンスに対して、次のプロパティを設定します。

Property プロパティ
AttributeName 列の論理名
Alias 結果に表示される列の一意の名前
AggregateType データを集計しない場合は、XrmAggregateType.None メンバーを使用します。 これはデフォルト値なので、集計を使用していない場合は設定する必要はありません。 QueryExpression を使用したデータの集計について学習する

返される各列は一意な名前でなければなりません。 規定では、クエリのテーブルに対して返される列名は、列 LogicalName の値です。 すべての列の論理名はテーブルごとに一意であるため、そのセット内で重複する名前は存在できません。

LinkEntity を使用して テーブルを結合すると、結合されたテーブルを表す LinkEntityEntityAlias プロパティ を設定できます。 LinkEntity.Columns プロパティ の列名は、次の命名規則に従います: {Linked table LogicalName or alias}.{Column LogicalName}。 これにより、列名の重複が防止されます。

ただし、列の別名を指定する場合は、 XrmAttributeExpression.Alias プロパティLinkEntity.EntityAlias または、テーブル論理名の値がエイリアス値の先頭に追加されません。 エイリアス値が一意であることを確認する必要があります。 値が一意でない場合は、次のエラーが発生する可能性があります。

名前: QueryBuilderDuplicateAlias
コード: 0x80041130
番号: -2147217104
メッセージ: < alias value > is not a unique alias. It clashes with an autogenerated alias or user provided alias

列エイリアスの例

この SimpleAliasOutput 例の方法では、列のエイリアスと論理名を使用しています。 このため、エイリアスを使用した結果は AliasedValue として返されます。 OptionSetValue または OptionSetValue のような型の値にアクセスするには、値をキャストする必要があります。

この例では、accountclassificationcodecreatedby、および createdon 列に対してのみエイリアスが指定されています。 name 列でエイリアスは使用されません。 このメソッドは、テーブルをレンダリングするために ConsoleTables NuGet パッケージ に依存します。

/// <summary>
/// Output the entity attribute values with aliases
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance</param>
static void SimpleAliasOutput(IOrganizationService service)
{
    QueryExpression query = new("account")
    {
        TopCount = 3,
        ColumnSet = new ColumnSet("name")
        {
            AttributeExpressions = {
                new XrmAttributeExpression{
                    AttributeName = "accountclassificationcode",
                    Alias = "classificationcode"
                 },
                 new XrmAttributeExpression{
                    AttributeName = "createdby",
                    Alias = "whocreated"
                 },
                 new XrmAttributeExpression{
                    AttributeName = "createdon",
                    Alias = "whencreated"
                 }
            }
        }
    };

    //Retrieve the data
    EntityCollection entityCollection = service.RetrieveMultiple(query: query);

    var table = new ConsoleTables.ConsoleTable("classificationcode", "whocreated", "whencreated", "name");

    foreach (var entity in entityCollection.Entities)
    {

        var code = ((OptionSetValue)entity.GetAttributeValue<AliasedValue>("classificationcode").Value).Value;
        var whocreated = ((EntityReference)entity.GetAttributeValue<AliasedValue>("whocreated").Value).Name;
        var whencreated = entity.GetAttributeValue<AliasedValue>("whencreated").Value;
        var companyname = entity.GetAttributeValue<string>("name");

        table.AddRow(code, whocreated, whencreated, companyname);

    }
    table.Write();
}

出力:

 ----------------------------------------------------------------------------------
 | code | whocreated           | whencreated           | companyname              |
 ----------------------------------------------------------------------------------
 | 1    | FirstName LastName   | 8/13/2023 10:30:08 PM | Fourth Coffee (sample)   |
 ----------------------------------------------------------------------------------
 | 1    | FirstName LastName   | 8/13/2023 10:30:10 PM | Litware, Inc. (sample)   |
 ----------------------------------------------------------------------------------
 | 1    | FirstName LastName   | 8/13/2023 10:30:10 PM | Adventure Works (sample) |
 ----------------------------------------------------------------------------------

AliasedValueクラス には、必要に応じて元の EntityLogicalNameAttributeLogicalName を示す 2 つのプロパティがあります。

エイリアスとフォーマットされた値の例

エイリアスを使用する列は AliasedValue を返します書式設定された値にアクセスするで説明したように、一部の列タイプでは、アプリケーションでの表示に適した文字列値を提供するために、 Entity.FormattedValues コレクション を使用して書式設定された文字列値も返されます。

次の静的 OutputQueryExpression 例メソッドは、データの各行の文字列値を抽出する方法を示しています。 この関数は、QueryExpression.ColumnSet データを使用して要求されている列を認識し、結果を処理して、アプリ (この場合は、 ConsoleTables NuGet パッケージ を使用してテーブルをレンダリングするコンソール アプリケーション) でレコード データを表示する最適な方法を見つけます。

/// <summary>
/// Renders the output of a query in a table for a console application
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance to use.</param>
/// <param name="query">The query to use</param>
/// <exception cref="Exception">
/// OutputQueryExpression requires all LinkEntity instances that contain columns specify an EntityAlias property.
/// </exception>
static void OutputQueryExpression(IOrganizationService service, QueryExpression query)
{
    //Retrieve the data
    EntityCollection entityCollection = service.RetrieveMultiple(query: query);

    var columns = GetQueryExpressionColumns(query);

    // Create the table using https://www.nuget.org/packages/ConsoleTables/2.5.0
    var table = new ConsoleTables.ConsoleTable(columns.ToArray());

    // Add the rows of the table
    entityCollection.Entities.ToList().ForEach(entity =>
    {
        table.Rows.Add(GetRowValues(columns, entity).ToArray());
    });

    // Write the table to the console
    table.Write();

    List<string> GetQueryExpressionColumns(QueryExpression query)
    {
        List<string> columns = new();

        columns.AddRange(GetColumns(query.ColumnSet));

        foreach (LinkEntity linkEntity in query.LinkEntities)
        {
            columns.AddRange(GetLinkEntityColumns(linkEntity));
        }

        return columns;
    }

    List<string> GetLinkEntityColumns(LinkEntity linkEntity)
    {
        if (string.IsNullOrWhiteSpace(linkEntity.EntityAlias))
        {
            if (linkEntity.Columns.Columns.Count != 0)
            {
                string message = "OutputQueryExpression method requires all ";
                message += "LinkEntity instances that contain columns ";
                message += "specify an EntityAlias property.";

                throw new Exception(message);
            }
        }

        List<string> columns = new();

        columns.AddRange(GetColumns(linkEntity.Columns, linkEntity.EntityAlias));

        foreach (LinkEntity le in linkEntity.LinkEntities)
        {
            columns.AddRange(GetColumns(le.Columns, le.EntityAlias));
        }
        return columns;
    }

    List<string> GetColumns(ColumnSet columnset, string alias = null)
    {
        List<string> columns = new();

        foreach (string column in columnset.Columns)
        {
            columns.Add(string.IsNullOrWhiteSpace(alias) ? column : $"{alias}.{column}");
        }

        foreach (XrmAttributeExpression item in columnset.AttributeExpressions)
        {
            columns.Add(item.Alias ?? item.AttributeName);
        }

        return columns;
    }

    List<string> GetRowValues(List<string> columns, Entity entity)
    {
        List<string> values = new();
        columns.ForEach(column =>
        {
            if (entity.Attributes.ContainsKey(column))
            {
                // Use the formatted value if it available
                if (entity.FormattedValues.ContainsKey(column))
                {
                    values.Add($"{entity.FormattedValues[column]}");
                }
                else
                {
                    // When an alias is used, the Aliased value must be converted
                    if (entity.Attributes[column] is AliasedValue aliasedValue)
                    {
                        values.Add($"{aliasedValue.Value}");
                    }
                    else
                    {
                        // Use the simple attribute value
                        values.Add($"{entity.Attributes[column]}");
                    }
                }
            }
            // Null values are not in the Attributes collection
            else
            {
                values.Add("NULL");
            }

        });
        return values;
    }
}

この関数を使用すると、任意の QueryExpression クエリの出力を表示できます。唯一の要件は、テーブルを結合するために使用される任意の LinkEntity に別名を指定することです。 たとえば、次のクエリには、結合されたテーブルにエイリアスおよびフォーマットされた値が含まれています。

static void OutputQueryExpressionExample(IOrganizationService service)
{
    // Specify a query:
    QueryExpression query = new("account")
    {
        TopCount = 3,
        ColumnSet = new ColumnSet("name")
        {
            AttributeExpressions = {
                new XrmAttributeExpression{
                    AttributeName = "accountclassificationcode",
                    Alias = "classificationcode"
                 }
            }
        },
        LinkEntities = {
            new LinkEntity()
            {
                LinkFromEntityName = "account",
                LinkToEntityName = "contact",
                LinkFromAttributeName = "primarycontactid",
                LinkToAttributeName = "contactid",
                JoinOperator = JoinOperator.Inner,
                EntityAlias = "person",
                Columns = new ColumnSet("fullname"){
                    AttributeExpressions = {
                    new XrmAttributeExpression{
                        AttributeName = "accountrolecode",
                        Alias = "role"
                        }
                    }
                }
            }
        }
    };

    // Use OutputQueryExpression
    OutputQueryExpression(service, query);
}

このクエリの結果は次のようになります。

 ----------------------------------------------------------------------------
 | name             | classificationcode | person.fullname | role           |
 ----------------------------------------------------------------------------
 | Fourth Coffee    | Large              | Susie Curtis    | Influencer     |
 ----------------------------------------------------------------------------
 | Litware, Inc.    | Medium             | Adele Vance     | Decision Maker |
 ----------------------------------------------------------------------------
 | Adventure Works  | Small              | Rafel Shillo    | Employee       |
 ----------------------------------------------------------------------------

次の手順

テーブルの結合方法について説明します。