Partager via


Sélectionner des colonnes à l’aide de QueryExpression

Important

Nous déconseillons fortement de renvoyer toutes les colonnes d’un tableau avec votre requête. Le renvoi de toutes les colonnes ralentira l’exécution de vos applications et peut provoquer des erreurs de délai d’attente. Vous devez spécifier le nombre minimum de colonnes à récupérer avec vos données. Si vous définissez la propriété ColumnSet.AllColumns sur true, les données de toutes les colonnes sont renvoyées. Si vous ne définissez aucune colonne, seule la valeur de clé primaire de l’enregistrement est renvoyée. Ceci est à l’opposé du comportement utilisé avec FetchXml, où toutes les colonnes sont renvoyées si vous n’en spécifiez aucune.

Utilisez la classe ColumnSet pour spécifier les noms des colonnes à renvoyer avec votre requête. Utilisez la valeur AttributeMetadata.LogicalName pour chaque colonne. Les valeurs des noms logiques sont toujours en minuscules.

Vous pouvez spécifier les colonnes avec le constructeur ColumnSet(String[]) lorsque vous initialisez le QueryExpression :

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

Et vous pouvez utiliser les méthodes ColumnSet.AddColumn ou ColumnSet.AddColumns pour ajouter des colonnes supplémentaires au Propriété QueryExpression.ColumnSet après l’initialisation de QueryExpression .

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

Notes

Certaines colonnes ne sont pas valides à lire. La propriété AttributeMetadata.IsValidForRead indique si une colonne est valide en lecture. Si vous incluez les noms de ces colonnes, aucune valeur n’est renvoyée.

La propriété ColumnSet.Columns est une Microsoft.Xrm.Sdk.DataCollection<string> qui étend la System.Collections.ObjectModel.Collection<T> class, vous pouvez donc également utiliser les méthodes de ces bases classes pour interagir avec les chaînes de la collection.

Sélectionnez les colonnes pour les tables jointes

Lorsque vous joignez des tables à l’aide de QueryExpression, vous utilisez la classe LinkEntity. La propriété LinkEntity.Columns est un ColumnSet, vous définirez donc les colonnes à renvoyer pour les tables jointes de la même manière.

Premières classes de champs liés

Si vous utilisez des classes de champs à liaison anticipée générées à l’aide de la commande pac modelbuilder avec le commutateur emitfieldsclasses activé, vous peut utiliser les constantes générées pour tous les noms de champs plutôt que d’utiliser les noms logiques directement sous forme de chaînes.

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

Cela permet d’éviter les erreurs d’exécution dues à la saisie d’un nom incorrect. En savoir plus sur :

Alias de colonne

Les alias de colonne sont généralement utilisés pour les opérations d’agrégation, mais ils permettent également de récupérer des lignes. Nous pouvons donc les présenter ici.

Ajoutez des XrmAttributeExpression instances à la collection ColumnSet.AttributeExpressions pour spécifier un nom de colonne unique pour les résultats renvoyés. Pour chaque instance, définissez ces propriétés :

Property Description
AttributeName Nom logique de la colonne
Alias Un nom unique pour la colonne à apparaître dans les résultats
AggregateType Lorsque vous n’agrégez pas de données, utilisez le membre XrmAggregateType.None . Il s’agit de la valeur par défaut, vous n’avez donc pas besoin de la définir si vous n’utilisez pas l’agrégation. En savoir plus sur l’agrégation de données avec QueryExpression

Chaque colonne renvoyée doit avoir un nom unique. Par défaut, les noms de colonnes renvoyés pour la table de votre requête sont les valeurs LogicalName des colonnes. Tous les noms logiques de colonnes sont uniques pour chaque table, il ne peut donc pas y avoir de noms en double dans cet ensemble.

Lorsque vous utilisez un LinkEntity à joindre des tables, vous pouvez définir le Propriété EntityAlias pour le LinkEntity représentant la table jointe. Les noms de colonnes dans le Propriété LinkEntity.Columns suivez cette convention de dénomination : {Linked table LogicalName or alias}.{Column LogicalName}. Cela évite les noms de colonne en double.

Cependant, lorsque vous spécifiez un alias de colonne à l’aide de Propriété XrmAttributeExpression.Alias, le LinkEntity.EntityAlias ou la valeur du nom logique de la table n’est pas ajoutée au début de la valeur de l’alias. Vous devez vous assurer que la valeur de l’alias est unique. Si la valeur n’est pas unique, vous pouvez vous attendre à cette erreur :

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

Exemple d’alias de colonne

Ce SimpleAliasOutput L’exemple de méthode utilise les alias et les noms logiques des colonnes. Pour cette raison, les résultats qui utilisent des alias sont renvoyés sous la forme AliasedValue. Pour accéder à la valeur de types comme OptionSetValue ou EntityReference, vous devez convertir la valeur.

Dans cet exemple, seules les alias sont spécifiés pour accountclassificationcode, createdby et createdon colonnes. La name colonne n’utilise pas d’alias. Cette méthode dépend du ConsoleTables NuGet package pour restituer la table.

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

Sortie :

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

La classe AliasedValue a deux propriétés qui vous indiquent les valeurs EntityLogicalName et AttributeLogicalName d’origine si vous en avez besoin.

Exemple de valeurs alias et formatées

Les colonnes qui utilisent un alias renvoient une AliasedValue. Comme expliqué dans Valeurs formatées Access, pour certains types de colonnes, les valeurs de chaîne formatées sont également renvoyées à l’aide de la collection Entity.FormattedValues pour fournir des valeurs de chaîne adaptées à l’affichage dans une application.

L’exemple de méthode statique OutputQueryExpression suivant montre comment extraire des valeurs de chaîne pour chaque ligne de données. Cette fonction utilise les QueryExpression.ColumnSet données pour savoir quelles colonnes sont demandées, puis traite les résultats pour trouver la meilleure façon d’afficher les données d’enregistrement dans une application, dans ce cas, une application console utilisant ConsoleTables NuGet package pour afficher une table.

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

Vous pouvez utiliser cette fonction pour afficher le résultat de n’importe quelle QueryExpression requête, la seule exigence étant que tout LinkEntity utilisé pour joindre des tables spécifie un alias. Par exemple, la requête suivante inclut des valeurs alias et formatées avec une table jointe :

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

Les résultats de cette requête pourraient ressembler à ceci :

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

Étapes suivantes

Découvrez comment joindre des tables.