In Microsoft Dataverse (Power Apps), there is often a need to retrieve summarized or aggregated data, such as counts, averages, sums, minimums, or maximums, rather than retrieving every individual record.
Traditional query methods using QueryExpression focus on row-level data retrieval and do not inherently support aggregate functions. This creates challenges for developers who need to generate meaningful business insights directly from server-side code or plugins.
How can developers leverage the QueryExpression class to perform aggregate queries efficiently within the constraints of the Dataverse platform?
We’ll walk through the process of performing aggregate operations using QueryExpression within Microsoft Dataverse. We’ll demonstrate how to implement server-side aggregation with the help of QueryExpression.
Using aggregate data with QueryExpression in C# allows you to retrieve summarized insights like the total number of active accounts, average revenue, or maximum order value directly from Dataverse. This is efficient for custom reports, dashboards, or automated tools, as it reduces data transfer and avoids processing large datasets in memory.
Create an authenticated IOrganizationService instance.
This query retrieves:
This approach minimizes network bandwidth usage and improves performance by pushing the aggregation logic to the server level.
Note: This functionality is supported in SDK versions targeting Microsoft Dataverse (via Xrm.Sdk), and requires usage of XrmAttributeExpression and XrmAggregateType, which are available in recent SDK packages.
var query = new QueryExpression("account") // Query on Account entity { ColumnSet = new ColumnSet(false) // No regular fields, only aggregate expressions { AttributeExpressions = { { new XrmAttributeExpression(attributeName : "revenue", alias : "Average", aggregateType : XrmAggregateType.Avg) }, // Average revenue { new XrmAttributeExpression(attributeName : "revenue", alias :"Count", aggregateType : XrmAggregateType.Count) }, // Count of records { new XrmAttributeExpression(attributeName : "revenue", alias :"Min", aggregateType : XrmAggregateType.Min) }, // Minimum revenue { new XrmAttributeExpression(attributeName : "revenue", alias :"Max", aggregateType : XrmAggregateType.Max) } // Maximum revenue } }, Criteria = new FilterExpression(LogicalOperator.And) // Filtering conditions { Conditions = { new ConditionExpression("statecode", ConditionOperator.Equal, 0), // Only active accounts new ConditionExpression("ownerid", ConditionOperator.Equal, new Guid("03b8f351-a246-f011-8779-7c1e520e8711")) // Specific owner } } }; var results = service.RetrieveMultiple(query); // Execute the query if (results != null && results.Entities != null & results.Entities.Count > 0) { Entity information = results.Entities[0]; Console.WriteLine("********************* Revenue Generated By USER 1 ********************"); Console.WriteLine($"********************* Average Revenue {((Money)((AliasedValue)information.Attributes["Average"]).Value).Value} ********************"); Console.WriteLine($"********************* Count Revenue {((AliasedValue)information.Attributes["Count"]).Value} ********************"); Console.WriteLine($"********************* Min Revenue {((Money)((AliasedValue)information.Attributes["Min"]).Value).Value} ********************"); Console.WriteLine($"********************* Max Revenue {((Money)((AliasedValue)information.Attributes["Max"]).Value).Value} ********************"); } else { Console.WriteLine("No Information Found"); }
When the above code is executed, it fetches aggregate data for the revenue field for active accounts owned by a specific user. The final output may appear as follows:
Using QueryExpression for aggregation:
Leveraging QueryExpression for aggregate data retrieval in C# offers a powerful, code-centric way to perform real-time analytics within Dynamics 365. While it supports essential aggregate functions like SUM, AVG, MIN, MAX, and COUNT, developers should be aware of its limitations—such as the lack of support for DISTINCT counts, cross-entity aggregation, and large dataset boundaries.
By combining the power of QueryExpression with post-processing in C# (e.g., LINQ), you can overcome most of these limitations without resorting to FetchXML. This keeps your codebase clean, strongly typed, and aligned with traditional .NET development practices, making it ideal for plugins, custom workflows, and background services within the Dataverse ecosystem.
The post Using Aggregate Functions with QueryExpression in Dynamics 365 first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.
Original Post https://www.inogic.com/blog/2025/06/using-aggregate-functions-with-queryexpression-in-dynamics-365/