Freigeben über


FetchXml-Beispielcode

Um die Verwendung von FetchXml mit C# auszuprobieren, können Sie die statischen OutputFetchRequest-Methoden in diesem Artikel verwenden, indem Sie die entsprechenden Schnellstartbeispiele anpassen:

Anmerkung

Beispielcode zum Abrufen von Daten auf Seiten finden Sie unter Beispiele für Auslagerungs-Cookies.

Sie können die folgende statische OutputFetchRequest-Methode verwenden, um FetchXml-Abfragen in einer Konsolenanwendung zu testen.

Die OutputFetchRequest-Methode zeigt, wie die FetchExpression-Klasse und die IOrganizationService.RetrieveMultiple-Methode verwendet werden, um eine EntityCollection zurückzugeben, die die angeforderten Daten enthält.

Die OutputFetchRequest-Methode hängt vom ConsoleTables-NuGet-Paket ab und erfordert, dass alle Entitäten oder Link-EntitätselementeAttributelemente enthalten sind, was eine bewährte Methode ist.

/// <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="fetchXml">The FetchXml query to use.</param>
static void OutputFetchRequest(IOrganizationService service, string fetchXml)
{
    FetchExpression fetchExpression = new(fetchXml);

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

    // Get column names from the FetchXml
    List<string> columns = GetColumns(fetchXml);

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

    /// <summary>
    /// Get a list of column names from the FetchXml
    /// </summary>
    /// <param name="fetchXml">The fetchXml query</param>
    /// <returns></returns>
    static List<string> GetColumns(string fetchXml)
    {
        XDocument fetchDoc = XDocument.Parse(fetchXml);

        XElement fetchElement = fetchDoc.Root;

        bool isAggregate = !(fetchElement?.Attributes("aggregate") == null &&
            (fetchElement?.Attribute("aggregate")?.Value == "true" ||
            fetchElement?.Attribute("aggregate")?.Value == "1"));

        // There can only be one entity element
        XElement entityElement = fetchElement.Element("entity");

        // Get the columns from the entity and any related link-entity elements
        return GetColumnsFromElement(element: entityElement, isAggregate: isAggregate);

    }

    /// <summary>
    /// Recursive function to get all column names from an entity or nested link-entity elements
    /// </summary>
    /// <param name="element">The entity or link-entity element</param>
    /// <param name="isAggregate">Whether the query uses aggregation</param>
    /// <param name="alias">The alias of the link-entity element</param>
    /// <returns></returns>
    static List<string> GetColumnsFromElement(XElement element, bool isAggregate, string? alias = null)
    {
        List<string> columns = new();

        // Get the attributes from the element
        foreach (XElement attribute in element.Elements("attribute"))
        {
            StringBuilder sb = new();


            // Prepend the alias for non-aggregate link-entities
            if (!string.IsNullOrWhiteSpace(alias) && !isAggregate)
            {
                sb.Append($"{alias}.");
            }

            // Use the attribute alias if there is one
            if (attribute.Attribute("alias") != null)
            {
                sb.Append(attribute.Attribute("alias")?.Value);
            }
            else
            {
                //Use the attribute name
                sb.Append(attribute.Attribute("name")?.Value);
            }

            columns.Add(sb.ToString());
        }

        // Whether the link-entity intersect attribute is true
        bool isIntersect = (element.Attribute("intersect") != null) &&
            (element.Attribute("intersect")?.Value == "true" ||
            element.Attribute("intersect")?.Value == "1");

        // The name of the element
        string elementName = element.Attribute("name")?.Value;
        // The type of element: 'entity' or 'link-entity'
        string elementType = element.Name.LocalName;

        // This method requires any non-intersect entity to have attributes
        if (columns.Count == 0 && !isIntersect)
        {
            // An non-intersect element with no attribute elements is technically valid,
            // but not supported by this method.
            throw new Exception($"No attribute elements in {elementType} element named '{elementName}'.");
        }

        // Look for any child link-entities
        foreach (XElement linkEntity in element.Elements("link-entity"))
        {
            // Use the alias if any
            string? linkEntityName;
            if (linkEntity.Attribute("alias") != null)
            {
                linkEntityName = linkEntity.Attribute("alias")?.Value;
            }
            else
            {
                linkEntityName = linkEntity.Attribute("name")?.Value;
            }

            // Recursive call for nested link-entity elements
            columns.AddRange(GetColumnsFromElement(linkEntity, isAggregate, linkEntityName));
        }

        return columns;
    }

    /// <summary>
    /// Returns the values of a row as strings
    /// </summary>
    /// <param name="columns">The names of the columns</param>
    /// <param name="entity">The entity with the data</param>
    /// <returns></returns>
    static 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) &&
                !string.IsNullOrWhiteSpace(entity.FormattedValues[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)
                    {
                        // When an EntityReference doesn't have a Name, show the Id
                        if (aliasedValue.Value is EntityReference lookup &&
                        string.IsNullOrWhiteSpace(lookup.Name))
                        {
                            values.Add($"{lookup.Id:B}");
                        }
                        else
                        {
                            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;
    }
}

SDK für .NET-Schnellstartbeispiel aktualisieren

Sie können das Beispiel Schnellstart: Eine SDK für .NET-Anforderung ausführen (C#) zum Testen von Abfragen mit den folgenden Schritten anpassen:

  1. ConsoleTables-NuGet-Paket installieren

  2. Fügen Sie die folgenden Anweisungen mithilfe von Anweisungen an den Anfang der Datei program.cs ein.

    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using System.Text;
    using System.Xml.Linq;
    
  3. Kopieren Sie die Methode OutputFetchRequest und fügen Sie sie unter der Methode Main ein.

  4. Bearbeiten Sie die Main-Methode, um Ihre Abfrage festzulegen, und verwenden Sie die OutputFetchRequest-Methode.

        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);
    
                    string fetchQuery = @"<fetch top='5'>
                        <entity name='account'>
                        <attribute name='accountclassificationcode' />
                        <attribute name='createdby' />
                        <attribute name='createdon' />
                        <attribute name='name' />
                        </entity>
                    </fetch>";
    
                    OutputFetchRequest(serviceClient, fetchQuery);
                }
                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();
        }
    

Lesen Sie die folgenden wichtigen Informationen zur Verwendung einer Verbindungszeichenfolge im Anwendungscode.

Wichtig

Microsoft empfiehlt, den sichersten verfügbaren Authentifizierungsflow zu verwenden. Der in diesem Artikel beschriebene Authentifizierungsablauf erfordert ein sehr hohes Maß an Vertrauen in die Anwendung und birgt Risiken, die in anderen Flows nicht vorhanden sind. Sie sollten diesen Flow nur verwenden, wenn andere, sicherere Flows, z. B. verwaltete Identitäten, nicht funktionsfähig sind.

Wenn Sie das Programm mit der OutputFetchRequest-Methode ausführen, sollte die Ausgabe wie folgt aussehen:

 ---------------------------------------------------------------------------------------------------------
 | accountclassificationcode | createdby          | createdon          | name                             |
 ---------------------------------------------------------------------------------------------------------
 | Default Value             | FirstName LastName | 3/25/2023 10:42 AM | Litware, Inc. (sample)           |
 ---------------------------------------------------------------------------------------------------------
 | Default Value             | FirstName LastName | 3/25/2023 10:42 AM | Adventure Works (sample)         |
 ---------------------------------------------------------------------------------------------------------
 | Default Value             | FirstName LastName | 3/25/2023 10:42 AM | Fabrikam, Inc. (sample)          |
 ---------------------------------------------------------------------------------------------------------
 | Default Value             | FirstName LastName | 3/25/2023 10:42 AM | Blue Yonder Airlines (sample)    |
 ---------------------------------------------------------------------------------------------------------
 | Default Value             | FirstName LastName | 3/25/2023 10:42 AM | City Power & Light (sample)      |
 ---------------------------------------------------------------------------------------------------------

Daten mithilfe von FetchXml abfragenFetchXML zum Abrufen von Daten verwendeBeispiel: Verwendung von FetchXML mit einem Paging-CookieBeispiel: Aggregation in FetchXML verwendenBeispiel: Abfragen zwischen FetchXML und QueryExpression konvertieren