Almanac
Microsoft/dataversePower Platform

Consultant KB for Microsoft Dataverse, the data layer under Dynamics 365 and the Power Platform: data model, security model, business logic, APIs and integration, search and queries, analytics and Fabric, ALM and solutions, administration, governance and compliance, and Dataverse as an agent data platform, plus cross-cutting decision guides. Implementation notes, configuration decisions and the gotchas that bite on real projects. Populated by the daily author agent from the Dataverse release plans, docs repo and product blog, plus the author's own consultant notes.

feature-virtual-table-providers.mdv1 · history
CurrentApplies to DeveloperUpdated last monthSource Microsoft Learn

What it does

A virtual table is a table definition in Dataverse with no physical storage behind it; rows are fetched from an external system at the moment they're needed. The data provider is what does the fetching — either one of the providers that ships with the platform, or a set of plug-ins you write yourself and register against the CRUD events.

Key facts

  • Two providers ship with Dataverse. The OData v4 provider is installed by default and supports create, read, update and delete. An Azure Cosmos DB provider is available from the marketplace.
  • A custom provider is a plug-in per operation — Create, Update, Retrieve, RetrieveMultiple, Delete — running in stage 30, the main core transaction stage that ordinary plug-in steps can't use.
  • You register the assembly and the plug-in types in the Plug-in Registration tool but you don't register steps. Configuration lives in the EntityDataProvider table.
  • Retrieve gets a description of the columns and related tables to fetch. RetrieveMultiple gets a QueryExpression, and the framework provides a QueryExpressionVisitor class for walking it.
  • The Microsoft.Xrm.Sdk.Data.dll assembly, from the Microsoft.CrmSdk.Data NuGet package, provides the mapping framework and a set of exception types — AuthenticationException, EndpointException, InvalidQueryException, ObjectNotFoundException, TimeoutException and others — that you're expected to throw rather than inventing your own.
  • Two development shapes: a generic provider that translates FetchXML into whatever the source understands and can be reused across instances, or a targeted LINQ provider tied to one known schema, which is far less work but must be rebuilt when that schema changes.
  • Only organisation-owned tables are supported. User-owned security filtering doesn't work, and column-level security isn't supported. Access is on or off per security role.
  • Every external row needs a GUID primary key that the provider can supply and map. The cleanest arrangement is for the source to actually use GUIDs.
  • Column selection in Retrieve and RetrieveMultiple isn't honoured — all attributes are returned regardless.
  • Not supported on virtual tables: auditing, Dataverse search, charts and dashboards, queues, offline caching, calculated and rollup columns, activities and business process flows. Virtual table lookup columns can be shown on a grid but can't be filtered or sorted on.
  • A virtual table can't be converted to a standard table afterwards, or the reverse.

When to use / skip

Use a virtual table when the external system must stay the system of record, the data volume makes replication unattractive, and users need to see it inside a model-driven app alongside real Dataverse data. Before writing a custom provider, seriously consider putting an OData v4 interface in front of the source instead and using the shipped provider — Microsoft suggests this themselves, and it converts a substantial .NET development effort into an integration layer that other things can also consume. Skip virtual tables entirely if the client needs search, charts, auditing, row-level security or offline on that data, because none of it works and there's no workaround.

Configuration decisions

  • Adapt the source to OData v4 and use the built-in provider, or write a custom one. This is the big decision and the OData route is right more often than teams expect.
  • Generic FetchXML-translating provider versus targeted LINQ provider, which is a trade of upfront effort against future schema fragility.
  • Which operations to support. Read-only is a legitimate and much simpler answer.
  • How the external identity maps to a GUID, and whether the source can be changed to hold one rather than you deriving one.
  • Where the connection credentials live and which identity the provider connects as, given that Dataverse row-level security won't be filtering anything.
  • Timeout and failure behaviour, since a slow external system now makes a Dataverse form slow.

Gotchas

  • Because column selection is ignored, every retrieve pulls every attribute. On a wide table over a chatty source, that's the performance problem you'll spend the project chasing.
  • Virtual table lookup columns on a grid are documented as slow, and Microsoft's own advice is to limit how many you include. Users add them to views and then report the view is broken.
  • Row-level security genuinely doesn't exist here. If the external data has per-user visibility rules, they have to be enforced inside the provider or not at all — and the provider connects as one identity.
  • No auditing means no answer to "who changed this and when" for anything on a virtual table. That's a compliance conversation, not a technical limitation to note in passing.
  • The provider runs in stage 30 in the transaction, so anything slow or unavailable upstream surfaces as a Dataverse error in the user's face.
  • The virtual-versus-standard decision is permanent. Getting it wrong means new tables and a migration.

Consultant notes

  • The honest positioning is that virtual tables are for surfacing external data in the UI, not for building on. As soon as a client wants to report on it, search it or secure it per user, the answer changes to replication.
  • Cost the custom provider properly. Microsoft's own prerequisites list is domain knowledge of the source, the Dataverse metadata model, the event framework and plug-in development — that's a senior developer for weeks, plus ongoing maintenance.
  • Get the external system's availability and latency SLA before agreeing to this. A virtual table inherits both, and the users will blame Dataverse.
  • Prototype the read path against realistic volumes early. The all-attributes behaviour is the thing that kills these projects, and it doesn't show up on a table with fifty test rows.

Worth revisiting if Microsoft adds column selection or row-level security to virtual tables — neither is supported as of July 2026.

Was this accurate?