Freigeben über


Spalten mit QueryExpression auswählen

Wichtig

Wir raten dringend davon ab, mit Ihrer Abfrage alle Spalten einer Tabelle zurückzugeben. Durch die Rückgabe aller Spalten werden Ihre Anwendungen langsamer ausgeführt und es kann zu Zeitüberschreitungsfehlern kommen. Sie sollten die Mindestanzahl der Spalten angeben, die mit Ihren Daten abgerufen werden sollen. Wenn Sie die ColumnSet.AllColumns-Eigenschaft auf „true“ festlegen, werden Daten für alle Spalten zurückgegeben. Wenn Sie keine Spalten festlegen, wird nur der Primärschlüsselwert für den Datensatz zurückgegeben. Dies ist das Gegenteil des Verhaltens bei Verwendung von FetchXml, wo alle Spalten zurückgegeben werden, wenn Sie keine angeben.

Verwenden Sie die ColumnSet-Klasse, um die Namen der Spalten anzugeben, die mit Ihrer Abfrage zurückgegeben werden sollen. Verwenden Sie für jede Spalte den Wert AttributeMetadata.LogicalName. Logische Namenswerte werden immer klein geschrieben.

Sie können die Spalten mit dem ColumnSet(String[])-Konstruktor angeben, wenn Sie die QueryExpression initialisieren:

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

Und Sie können die Methoden ColumnSet.AddColumn oder ColumnSet.AddColumns verwenden, um der QueryExpression.ColumnSet-Eigenschaft nach der Initialisierung von QueryExpression weitere Spalten hinzuzufügen.

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

Hinweis

Einige Spalten können nicht gelesen werden. Die AttributeMetadata.IsValidForRead-Eigenschaft gibt an, ob eine Spalte gelesen werden kann. Wenn Sie die Namen für diese Spalten miteinbeziehen, werden keine Werte zurückgegeben.

Die ColumnSet.Columns-Eigenschaft ist eine Microsoft.Xrm.Sdk.DataCollection<Zeichenfolge>, welche die System.Collections.ObjectModel.Collection<T>-Klasse erweitert, sodass Sie auch die Methoden dieser Basisklassen verwenden können, um mit den Zeichenfolgen in der Sammlung zu interagieren.

Spalten für verknüpfte Tabellen auswählen

Wenn Sie Tabellen mit QueryExpression verknüpfen, verwenden Sie die LinkEntity-Klasse. Die LinkEntity.Columns-Eigenschaft ist ein ColumnSet, daher legen Sie die für die verknüpften Tabellen zurückzugebenden Spalten auf die gleiche Weise fest.

Frühe gebundene Feldklassen

Wenn Sie früh gebundene Feldklassen verwenden, die mit dem pac modelbuilder-Befehl und aktiviertem Schalter emitfieldsclasses generiert wurden, können Sie die generierten Konstanten für alle Feldnamen verwenden, anstatt die logischen Namen direkt als Zeichenfolgen zu nehmen.

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

Dadurch werden Laufzeitfehler aufgrund der Eingabe falscher Namen vermieden. Weitere Informationen zu:

Spaltenaliasse

Spaltenaliase werden typischerweise für Aggregationsvorgänge verwendet, sie funktionieren aber auch zum Abrufen von Zeilen, sodass wir sie hier einführen können.

Fügen Sie der Sammlung ColumnSet.AttributeExpression XrmAttributeExpression-Instanzen hinzu, um einen eindeutigen Spaltennamen für die zurückgegebenen Ergebnisse anzugeben. Legen Sie für jede Instanz die folgenden Eigenschaften fest:

Eigenschaften Beschreibung
AttributeName Der logische Name der Spalte
Alias Ein eindeutiger Name für die Spalte, der in den Ergebnissen angezeigt werden soll
AggregateType Wenn Sie keine Daten aggregieren, verwenden Sie das XrmAggregateType.None-Mitglied. Dies ist der Standardwert. Sie müssen ihn daher nicht festlegen, wenn Sie keine Aggregation verwenden. Weitere Informationen über das Aggregieren von Daten mit QueryExpression

Jede Spalte gibt einen eindeutigen Namen zurück. Standardmäßig sind die für die Tabelle Ihrer Abfrage zurückgegebenen Spaltennamen die LogicalName-Werte der Spalte. Alle logischen Spaltennamen sind für jede Tabelle eindeutig, daher kann es in diesem Satz keine doppelten Namen geben.

Wenn Sie eine LinkEntity zum Verknüpfen von Tabellen verwenden, können Sie die EntityAlias-Eigenschaft auf die LinkEntity festlegen, die für die verknüpfte Tabelle stellt. Die Spaltennamen in der LinkEntity.Columns-Eigenschaft folgen diesen Namenskonvention: {Linked table LogicalName or alias}.{Column LogicalName}. Dies verhindert doppelte Spaltennamen.

Wenn Sie jedoch ein Spaltenalias mit der XrmAttributeExpression.Alias-Eigenschaft angeben, wird der LinkEntity.EntityAlias oder der Wert des logischen Tabellennamens dem Aliaswert nicht vorangestellt. Sie müssen sicherstellen, dass der Aliaswert eindeutig ist. Wenn der Wert nicht eindeutig ist, erhalten Sie wahrscheinlich diesen Fehler:

Name: QueryBuilderDuplicateAlias
Code: 0x80041130
Nummer: -2147217104
Meldung: < alias value > is not a unique alias. It clashes with an autogenerated alias or user provided alias

Beispiel für Spaltenaliase

Die SimpleAliasOutput-Beispielmethode verwendet Aliase und die logischen Namen der Spalten. Aus diesem Grund werden die Ergebnisse, die Aliase verwenden, wie folgt zurückgegeben: AliasedValue. Um auf den Wert von Typen wie OptionSetValue oder EntityReference zuzugreifen, müssen Sie den Wert umwandeln.

In diesem Beispiel sind nur für die Spalten accountclassificationcode, createdby und createdon Aliase angegeben. Die name-Spalte verwendet keinen Alias. Diese Methode hängt zum Rendern der Tabelle vom ConsoleTables NuGet-Paket ab.

/// <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();
}

Ausgabe:

 ----------------------------------------------------------------------------------
 | 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) |
 ----------------------------------------------------------------------------------

Der AliasedValue-Klasse hat zwei Eigenschaften, die Ihnen den ursprünglichen EntityLogicalName und AttributeLogicalName verraten, wenn Sie sie brauchen.

Beispiel für Aliaswerte und formatierte Werte

Spalten, die einen Alias verwenden, geben einen AliasedValue zurück. Wie unter Zugriff auf formatierte Werte erläutert, werden für einige Spaltentypen auch formatierte Zeichenfolgenwerte mithilfe der Entity.FormattedValues-Sammlung zurückgegeben, um Zeichenfolgenwerte bereitzustellen, die für die Anzeige in einer Anwendung geeignet sind.

Die folgende statische OutputQueryExpression-Beispielmethode zeigt, wie Zeichenfolgenwerte für die einzelnen Datenzeilen extrahiert werden. Diese Funktion ermittelt anhand der QueryExpression.ColumnSet-Daten, welche Spalten angefordert werden, und verarbeitet dann die Ergebnisse, um die beste Möglichkeit zum Anzeigen der Datensatzdaten in einer App zu ermitteln. In diesem Fall handelt es sich um eine Konsolenanwendung, die das ConsoleTables NuGet-Paket zum Rendern einer Tabelle verwendet.

/// <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;
    }
}

Mit dieser Funktion können Sie die Ausgabe jeder beliebige QueryExpression-Abfrage anzeigen. Die einzige Voraussetzung ist, dass für jede LinkEntity, die zum Verknüpfen von Tabellen verwendet wird, ein Alias angegeben wird. Die folgende Abfrage enthält beispielsweise Alias- und formatierte Werte mit einer verknüpften Tabelle:

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);
}

Die Ergebnisse dieser Abfrage könnten wie folgt aussehen:

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

Nächste Schritte,

Informationen zum Verknüpfen von Tabellen.