Sam February 11, 2026 0

When working with Dataverse, developers often begin with QueryExpression for programmatic data retrieval.

However, as solutions mature, requirements evolve beyond simple record retrieval.

Real-world systems require:

  • Revenue totals
  • Record counts
  • Average values
  • Grouped datasets
  • Date-based reporting
  • Dashboard analytics

This is where FetchXML becomes essential.

FetchXML is Dataverse’s most powerful query language for analytics and reporting scenarios.

In this deep dive, we’ll explore:

  • FetchXML fundamentals
  • Aggregates (SUM, COUNT, AVG, MIN, MAX)
  • Group By queries
  • Date grouping
  • Filters in aggregates
  • Reading results in C#
  • Performance best practices

What Is FetchXML?

FetchXML is an XML-based query language used to retrieve data from Dataverse.

It is used across multiple Microsoft technologies:

  • Advanced Find
  • Power Automate
  • SSRS Reports
  • Power Pages
  • SDK integrations
  • Dashboards

Unlike QueryExpression, FetchXML supports database-level aggregation.

Basic FetchXML Structure

<fetch>
<entity name="account">
<attribute name="name" />
</entity>
</fetch>

Core components:

ElementPurpose
fetchRoot query node
entityPrimary table
attributeColumns
filterConditions
link-entityJoins

Enabling Aggregates

To perform aggregation, set:

aggregate="true"

Example:

<fetch aggregate="true">

This tells Dataverse to compute results instead of returning raw records.

COUNT Aggregate

Scenario

Count total Active Accounts.

<fetch aggregate="true">
<entity name="account">

<attribute name="accountid"
alias="accountcount"
aggregate="count" />

<filter>
<condition attribute="statecode"
operator="eq"
value="0" />
</filter>

</entity>
</fetch>

Reading COUNT in C#

var count = (int)((AliasedValue)
results.Entities[0]["accountcount"]).Value;

Aggregate results always return AliasedValue.

SUM Aggregate

Scenario

Total Estimated Revenue.

<fetch aggregate="true">
<entity name="opportunity">

<attribute name="estimatedvalue"
alias="totalrevenue"
aggregate="sum" />

</entity>
</fetch>

Reading SUM Result

var revenue = ((Money)((AliasedValue)
results.Entities[0]["totalrevenue"]).Value).Value;

Money fields must be cast to Money first.

AVG Aggregate

<attribute name="estimatedvalue"
alias="averagevalue"
aggregate="avg" />

Useful for sales performance metrics.

MIN / MAX Aggregates

<attribute name="estimatedvalue"
alias="maxvalue"
aggregate="max" />

<attribute name="estimatedvalue"
alias="minvalue"
aggregate="min" />

Used for range analysis.

Group By Queries

Aggregates become significantly more powerful when grouped.

Scenario — Revenue by Account

<fetch aggregate="true">
<entity name="opportunity">

<attribute name="estimatedvalue"
alias="totalrevenue"
aggregate="sum" />

<attribute name="parentaccountid"
alias="account"
groupby="true" />

</entity>
</fetch>

Each result row represents one Account group.

Reading Grouped Results

foreach (var entity in results.Entities)
{
var account = ((EntityReference)
((AliasedValue)entity["account"]).Value).Name;

var revenue = ((Money)
((AliasedValue)entity["totalrevenue"]).Value).Value;
}

Multiple Column Grouping

Example:

Revenue grouped by:

  • Account
  • Owner
<attribute name="parentaccountid"
alias="account"
groupby="true" />

<attribute name="ownerid"
alias="owner"
groupby="true" />

Creates composite grouping.

Date Grouping

FetchXML supports time-based grouping — extremely useful for dashboards.

Opportunities by Year

<attribute name="createdon"
alias="year"
groupby="true"
dategrouping="year" />

Supported values:

ValueUse Case
dayDaily metrics
weekWeekly trends
monthSales reporting
quarterFinancial reporting
yearAnnual performance

Filtering Aggregate Queries

Filters apply before aggregation.

<filter>
<condition attribute="statecode"
operator="eq"
value="0" />
</filter>

This ensures only relevant records are aggregated.

Joins in Aggregate Queries

FetchXML supports joins inside aggregates.

Example — Revenue by Account Industry

<link-entity name="account"
from="accountid"
to="parentaccountid"
link-type="inner">

<attribute name="industrycode"
alias="industry"
groupby="true" />

</link-entity>

This allows cross-table grouping.

Ordering Aggregate Results

You can sort grouped results.

<order alias="totalrevenue"
descending="true" />

Useful for leaderboard-style reports.

Executing FetchXML in C#

var fetchXml = @"<fetch aggregate='true'> ... </fetch>";

var results = service.RetrieveMultiple(
new FetchExpression(fetchXml)
);

Performance Benefits

FetchXML aggregates execute at SQL level.

Benefits:

  • No record looping
  • Reduced network payload
  • Faster query execution
  • Scales to millions of rows

Best Practices

✔ Always use alias for aggregates
✔ Expect AliasedValue in results
✔ Filter before grouping
✔ Limit grouped columns
✔ Avoid aggregates in synchronous plugins
✔ Use for dashboards & reports

Plugin Performance Warning

Aggregates inside plugins can cause:

  • SQL load spikes
  • Timeouts
  • Transaction delays

Better alternatives:

  • Power BI
  • Synapse Link
  • Data Export
  • Azure Functions

Common Mistakes

MistakeImpact
Missing aliasQuery failure
Wrong type castingRuntime error
Aggregates in pluginsPerformance issues
No filtersLarge SQL scans

Real-World Use Cases

  • Sales revenue dashboards
  • Case volume reports
  • SLA breach analytics
  • Opportunity forecasts
  • Activity productivity tracking

FetchXML powers most enterprise reporting in Dataverse.

Conclusion

FetchXML is the analytics engine of Dataverse querying.

While QueryExpression excels at transactional retrieval, FetchXML unlocks:

  • Aggregation
  • Grouping
  • Date analytics
  • Reporting datasets

Mastering FetchXML ensures you can build scalable dashboards, reports, and enterprise insights directly on Dataverse data.

Category: