---
# === IDENTITY ===
id: business/erp-integration/dynamics-365-virtual-entities/2026
canonical_question: "What are Dynamics 365 Virtual Entities - cross-system federation, CRUD capabilities, limitations?"
aliases:
  - "Dynamics 365 virtual tables Dataverse external data without replication"
  - "How do Dataverse virtual entities federate data from Finance and Operations?"
  - "Virtual table limitations in Dataverse — no auditing, no search, organization-owned only"
  - "OData v4 Data Provider for Dataverse virtual tables CRUD support"
entity_type: erp_integration
domain: business > erp-integration > dynamics-365-virtual-entities
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === SYSTEM PROFILE ===
systems:
  - name: "Microsoft Dataverse"
    vendor: "Microsoft"
    version: "2024 Release Wave 2+"
    edition: "All licensed Power Platform environments"
    deployment: cloud
    api_surface: "OData v4, Web API, Custom Data Providers"
  - name: "Dynamics 365 Finance & Operations"
    vendor: "Microsoft"
    version: "10.0.12+"
    edition: "Finance, Supply Chain Management, Human Resources, Commerce"
    deployment: cloud
    api_surface: "OData (via CDSVirtualEntityAdapterService)"

# === VERIFICATION ===
last_verified: 2026-03-01
confidence: 0.91
version: 1.0
first_published: 2026-03-01

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: volatile
  last_breaking_change: "2024 Wave 2 — Virtual Table Creation Wizard preview; 10.0.36 — user-based API limits removed"
  next_review: 2026-08-28
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "Only organization-owned tables supported — user-owned security filtering and field-level security not available"
  - "External data source must provide GUID primary keys (Edm.Guid) — integer or string IDs cannot map to Dataverse unique identifiers"
  - "No auditing, search, charts, dashboards, queues, offline caching, or business process flows on virtual tables"
  - "Calculated and rollup columns not supported — all calculations must be performed on the external side"
  - "Cannot convert between virtual and standard (non-virtual) tables after creation"
  - "F&O virtual entities: Dataverse and F&O must be on the same Microsoft Entra tenant; co-locate in same Azure region for <30ms latency"
  - "Dataverse service protection API limits still apply to virtual entity calls even when F&O endpoints are exempt from their own throttling"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs to replicate data into Dataverse for offline access, auditing, or complex security"
    use_instead: "business/erp-integration/dynamics-365-dual-write-capabilities/2026"
  - condition: "User needs bulk data migration or high-volume ETL from F&O"
    use_instead: "business/erp-integration/dynamics-365-dmf-import-export/2026"
  - condition: "User needs direct Dataverse Web API CRUD without external federation"
    use_instead: "business/erp-integration/dynamics-365-dataverse-api-capabilities/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: integration_pattern
    question: "What integration pattern do you need?"
    type: choice
    options:
      - "real-time sync (individual records, <1s latency)"
      - "batch/bulk (scheduled, high volume)"
      - "event-driven (webhook, CDC, platform events)"
      - "file-based (CSV/XML import/export)"
  - key: data_volume
    question: "What's your daily data volume?"
    type: choice
    options:
      - "< 1,000 records/day"
      - "1,000-100,000 records/day"
      - "> 100,000 records/day"
  - key: direction
    question: "What's the data flow direction?"
    type: choice
    options:
      - "inbound (writing to this ERP)"
      - "outbound (reading from this ERP)"
      - "bidirectional sync"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/business/erp-integration/dynamics-365-virtual-entities/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-03-01)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "business/erp-integration/dynamics-365-dataverse-api-capabilities/2026"
      label: "Dataverse Web API for direct CRUD operations on native Dataverse tables"
    - id: "business/erp-integration/dynamics-365-web-api-capabilities/2026"
      label: "Dynamics 365 Web API for F&O OData endpoint access"
  solves: []
  alternative_to:
    - id: "business/erp-integration/dynamics-365-dual-write-capabilities/2026"
      label: "Dual Write replicates data bidirectionally; virtual entities federate without replication"
  often_confused_with:
    - id: "business/erp-integration/dynamics-365-dual-write-capabilities/2026"
      label: "Dual Write copies data into Dataverse; virtual entities read/write through to the external source in real time"

# === SOURCES ===
sources:
  - id: src1
    title: "Get started with virtual tables (entities) — Microsoft Dataverse"
    author: Microsoft
    url: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/virtual-entities/get-started-ve
    type: official_docs
    published: 2026-01-07
    reliability: authoritative
  - id: src2
    title: "Virtual entities overview — Finance & Operations"
    author: Microsoft
    url: https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/power-platform/virtual-entities-overview
    type: official_docs
    published: 2026-01-21
    reliability: authoritative
  - id: src3
    title: "Enable Microsoft Dataverse virtual entities — Finance & Operations"
    author: Microsoft
    url: https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/power-platform/enable-virtual-entities
    type: official_docs
    published: 2026-01-21
    reliability: authoritative
  - id: src4
    title: "Use the virtual table OData v4 Data Provider with Microsoft Dataverse"
    author: Microsoft
    url: https://learn.microsoft.com/en-us/power-apps/maker/data-platform/virtual-entity-odata-provider-requirements
    type: official_docs
    published: 2021-08-11
    reliability: authoritative
  - id: src5
    title: "Service protection API limits — Finance & Operations"
    author: Microsoft
    url: https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/service-protection-api-limits
    type: official_docs
    published: 2026-01-20
    reliability: authoritative
  - id: src6
    title: "Optimize Dataverse virtual table queries — Human Resources"
    author: Microsoft
    url: https://learn.microsoft.com/en-us/dynamics365/human-resources/hr-developer-optimize-virtual-table-queries
    type: official_docs
    published: 2021-04-02
    reliability: authoritative
  - id: src7
    title: "Dataverse Virtual Tables CRUD operations"
    author: Dynamics Chronicles
    url: https://dynamics-chronicles.com/article/dataverse-virtual-tables-crud-operations
    type: technical_blog
    published: 2024-01-15
    reliability: moderate_high
  - id: src8
    title: "Custom virtual table data providers — Microsoft Dataverse"
    author: Microsoft
    url: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/virtual-entities/custom-ve-data-providers
    type: official_docs
    published: 2026-01-07
    reliability: authoritative
---

# Dynamics 365 Virtual Entities: Cross-System Federation, CRUD Capabilities & Limitations

## TL;DR

- **Bottom line**: Virtual entities (virtual tables) let Dataverse surface external data as native tables without replication — full CRUD supported via OData v4 provider, Azure Cosmos DB provider, or custom plug-in providers. [src1]
- **Key limit**: External data sources must expose GUID primary keys (`Edm.Guid`) — integer or string IDs cannot map to Dataverse unique identifiers. [src1, src4]
- **Watch out for**: No auditing, no search, no calculated/rollup columns, no field-level security, and only organization-owned security mode — these are non-negotiable platform constraints. [src1]
- **Best for**: Real-time federated read/write access to external data (F&O, SQL, OData endpoints, Cosmos DB) from Power Apps, Power Automate, and Dataverse APIs without maintaining duplicate data. [src2]
- **Authentication**: F&O virtual entities use service-to-service (S2S) calls via Microsoft Entra application; OData v4 provider supports custom header/query string auth parameters. [src2, src4]

## System Profile

Dataverse virtual entities are a platform-level feature of Microsoft Dataverse that project external data as if it were native Dataverse tables. The external data is never copied — every Create, Retrieve, RetrieveMultiple, Update, and Delete operation is translated into a call to the external data source in real time. [src1]

For Finance & Operations (F&O) apps specifically, Microsoft provides a dedicated virtual entity provider that maps all OData-enabled F&O entities into Dataverse. This is the primary mechanism for cross-system federation between customer engagement apps (Sales, Service, Marketing) and F&O apps (Finance, Supply Chain Management, Human Resources). [src2]

| Property | Value |
|---|---|
| **Vendor** | Microsoft |
| **System** | Microsoft Dataverse + Dynamics 365 Finance & Operations |
| **API Surface** | OData v4 Data Provider (built-in), Azure Cosmos DB provider (Marketplace), Custom Data Providers (.NET plug-ins) |
| **Current Version** | Dataverse 2024 Wave 2+; F&O 10.0.12+ |
| **Editions Covered** | All licensed Power Platform environments; F&O: Finance, Supply Chain, HR, Commerce |
| **Deployment** | Cloud (on-premises/development environments excluded from service protection) |
| **API Docs** | [Virtual Tables (Dataverse)](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/virtual-entities/get-started-ve) |
| **Status** | GA |

## API Surfaces & Capabilities

Virtual entities operate through data providers that translate Dataverse operations into external system calls. Three provider types are available: [src1, src4, src8]

| Data Provider | Protocol | Best For | CRUD Support | Real-time? | External Auth | Notes |
|---|---|---|---|---|---|---|
| OData v4 (built-in) | HTTPS/OData | Any OData v4 endpoint (SQL, custom APIs) | Full CRUD | Yes | Header/query string params | Default provider; maps Edm types to Dataverse types [src4] |
| Azure Cosmos DB | HTTPS/REST | Document databases (Cosmos DB) | Full CRUD | Yes | Connection string | Available from Azure Marketplace [src1] |
| Custom Data Provider | .NET Plug-ins | Any data source (JDBC, gRPC, proprietary) | Full CRUD via plug-in registration | Yes | Developer-defined | Register plug-ins for Create, Retrieve, RetrieveMultiple, Update, Delete [src8] |
| F&O Virtual Entity Provider | SSL/TLS 1.2 S2S | Finance & Operations OData entities | Full CRUD | Yes | Microsoft Entra S2S (app registration) | CDSVirtualEntityAdapterService translates queries; F&O business logic invoked [src2] |

## Rate Limits & Quotas

### Per-Request Limits

Virtual entity calls are subject to limits on both the Dataverse side and the external system side. [src5, src6]

| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Column selection | Return all columns (no server-side $select pruning) | Dataverse virtual tables | `$select` is not applied server-side — all attributes are returned; use client-side filtering [src1] |
| Foreign key expansion | Significant latency per navigation property | Dataverse virtual tables | Each FK column triggers additional round-trip to external source [src6] |
| OData timeout | Configurable (default 30s) | OData v4 Data Provider | Set in data source configuration; affects all CRUD operations [src4] |
| F&O latency overhead | <30ms per call (co-located) | F&O virtual entities | Requires same Azure region for Dataverse and F&O environments [src2] |

### Rolling / Daily Limits (F&O Backend)

| Limit Type | Value | Window | Notes |
|---|---|---|---|
| Requests per user per web server | 6,000 | 5-minute sliding window | Per throttling key (user + application ID) [src5] |
| Combined execution time per user | 1,200 seconds (20 min) | 5-minute sliding window | Across all requests for the user [src5] |
| Concurrent requests per user | 52 | Per web server | Default; multiple web servers available in production [src5] |
| Resource-based throttling | Dynamic | Continuous | Triggered by high CPU/memory utilization across all integrations [src5] |

**Important**: F&O virtual entity calls are exempt from F&O service protection API limits when Power Platform integration is enabled. However, Dataverse service protection API limits still apply to the Dataverse side of the request. [src5]

### Dataverse Service Protection Limits

| Limit Type | Value | Window | Notes |
|---|---|---|---|
| API requests per user | 6,000 | 5-minute sliding window | Applies to all Dataverse API calls including virtual entity operations |
| Concurrent requests | 52 | Per connection | Shared with all Dataverse operations |

## Authentication

| Flow | Use When | Mechanism | Notes |
|---|---|---|---|
| F&O S2S (Microsoft Entra) | F&O virtual entities in Dataverse | Microsoft Entra app registration → S2S token | CDSVirtualEntityApplication security role required; user identity passed via Dataverse to F&O [src2] |
| OData v4 header auth | External OData endpoints | Custom header parameters | Up to 10 header or query string parameters configurable [src4] |
| OData v4 query string auth | External OData endpoints | Custom query string parameters | Same 10-parameter limit; toggle between header and query string [src4] |
| Custom provider auth | Any external system | Developer-implemented | Handle auth in your .NET plug-in code [src8] |

### Authentication Gotchas

- F&O S2S application should have access **only** to CDSVirtualEntityAdapterService and the catalog entity — broader access is a security anti-pattern. The CDSVirtualEntityApplication security role provides exactly these privileges. [src2]
- Dataverse passes the invoking user's identity to F&O during S2S calls. The F&O query runs in that user's security context — ensure the mapped F&O user has correct entity/row-level permissions. [src2]
- For Power Apps portals accessing F&O virtual entities, portal users must have the CDSVirtualEntityAuthorizedPortalUser role but must NOT have system administrator or security administrator roles. [src2]
- The OData v4 Data Provider cannot connect to another Dataverse environment — only to non-Dataverse OData endpoints. [src4]

## Constraints
<!-- Agents: read this section before recommending any integration approach from this unit.
     These are hard constraints that must not be violated. -->

- **Organization-owned only**: Virtual tables support only organization-owned security mode (on/off per user role). User-owned security filtering and field-level security are not available. [src1]
- **GUID primary key required**: All external tables must expose a GUID primary key. `Edm.Int32` and `Edm.String` cannot map to Dataverse unique identifiers. [src1, src4]
- **No auditing**: Changes to virtual entity records are not captured in Dataverse audit logs. [src1]
- **No search**: Virtual tables are excluded from Dataverse search because they don't persist data. [src1]
- **No calculated/rollup columns**: Computed fields must be implemented on the external side. [src1]
- **No charts/dashboards**: Virtual table data cannot power Dataverse charts or dashboards. [src1]
- **Immutable table type**: A virtual table cannot be converted to a standard table, and vice versa, after creation. [src1]
- **No offline caching**: Virtual table values are never cached locally — always fetched live. [src1]
- **Cannot represent activities or support BPFs**: Virtual tables cannot be activity tables and don't support business process flows. [src1]
- **F&O tenant restriction**: Dataverse and F&O must be on the same Microsoft Entra tenant. [src2]

## Integration Pattern Decision Tree

```
START — User needs to access external data from Dataverse/Power Platform
├── Does the user need data replicated INTO Dataverse?
│   ├── YES — need auditing, search, calculated fields, or offline access
│   │   ├── Real-time bidirectional? → Dual Write
│   │   └── Batch ETL? → Data Management Framework (DMF) or Azure Synapse Link
│   └── NO — federated read/write to external source is acceptable
│       ├── Is the external source Finance & Operations?
│       │   ├── YES → F&O Virtual Entities (built-in provider)
│       │   │   ├── Enable Power Platform integration
│       │   │   ├── Install MicrosoftOperationsVESupport solution
│       │   │   └── Make entities visible via catalog
│       │   └── NO ↓
│       ├── Does the external source expose OData v4?
│       │   ├── YES → OData v4 Data Provider (built-in)
│       │   │   ├── Verify Edm.Guid primary keys
│       │   │   └── Configure data source URI + auth params
│       │   └── NO ↓
│       ├── Is the external source Azure Cosmos DB?
│       │   ├── YES → Cosmos DB provider (from Marketplace)
│       │   └── NO ↓
│       └── Custom Data Provider (.NET plug-in development required)
│           ├── Implement Create, Retrieve, RetrieveMultiple, Update, Delete plug-ins
│           └── Register via Plug-in Registration Tool
├── Data volume considerations
│   ├── < 1,000 records/day → Virtual entities are fine; minimal latency overhead
│   ├── 1,000-10,000 records/day → Optimize with $select, pagination, narrow column sets
│   └── > 10,000 records/day → Consider Dual Write or DMF instead; virtual entity query cost scales linearly
└── Need charts, dashboards, search, or auditing on this data?
    ├── YES → Cannot use virtual entities; replicate data to native Dataverse tables
    └── NO → Virtual entities are the right choice
```

## Quick Reference

### F&O Virtual Entity Setup Checklist

| Step | Action | Where | Verification |
|---|---|---|---|
| 1 | Enable Power Platform integration | Power Platform admin center → Environment link | Environment shows as "Linked" |
| 2 | Install required solutions | Auto-installed with integration | Verify Dynamics365Company, MicrosoftOperationsVESupport, MicrosoftOperationsERPCatalog, MicrosoftOperationsERPVE in Solutions |
| 3 | Find entity in catalog | Advanced Find → "Available finance and operations entities" | Entity appears in list |
| 4 | Make entity visible | Open entity → check "Visible" checkbox → Save | Virtual entity appears in Advanced Find and Power Apps |
| 5 | Refresh metadata (after F&O changes) | Open entity → check "Refresh" checkbox → Save | Updated columns appear |
| 6 | Reference in ISV solution | Add existing → Table → select virtual entity | Hard dependency on MicrosoftOperationsERPVE |

[src3]

### OData v4 Provider Data Type Mappings

| OData EDM Type | Dataverse Type | Supported? | Notes |
|---|---|---|---|
| Edm.Guid | Unique Identifier | Yes | Required for primary key mapping [src4] |
| Edm.String | Single/Multi Line Text | Yes | |
| Edm.Int32 | Whole Number | Yes | Cannot map to primary key [src4] |
| Edm.Int64 | Whole Number | Yes | |
| Edm.Decimal | Decimal/Currency | Yes | |
| Edm.Double | Floating Point | Yes | |
| Edm.Boolean | Two Options | Yes | |
| Edm.DateTime | Date and Time | Yes | |
| Edm.DateTimeOffset | Date and Time | Yes | |
| Edm.Binary | — | No | Not supported for mapping [src4] |
| Edm.Float | — | No | Not supported [src4] |
| Edm.Int16 | — | No | Not supported [src4] |
| Edm.Byte / Edm.SByte | — | No | Not supported [src4] |
| Edm.Time | — | No | Not supported [src4] |

## Step-by-Step Integration Guide

### 1. Configure OData v4 Virtual Table Data Source

Create a data source pointing to your external OData endpoint. [src4]

1. Navigate to **Settings** > **Administration** > **Virtual Entity Data Sources**
2. Click **New** and select **OData v4 Data Provider**
3. Set the **URI** to your OData service root (e.g., `https://myservice.azurewebsites.net/odata/`)
4. Set **Timeout** (default 30 seconds)
5. Choose **Pagination mode**: client-side (default) or server-side ($skiptoken)
6. Add authentication headers/query strings if needed (up to 10 parameters)
7. Save

**Verify**: Navigate to Virtual Entity Data Sources list → new source appears with status Active.

### 2. Create the Virtual Table Definition

Map your external entity to a Dataverse virtual table. [src1]

1. Go to **Power Apps** → **Tables** → **New table** → **Virtual table**
2. Select the data source created in Step 1
3. Map the entity name and primary key (must be Edm.Guid)
4. Map columns: external field names to Dataverse column definitions
5. Define relationships (lookups) to other tables if needed

**Verify**: Open the new table in **Advanced Find** → records from external source appear.

### 3. Query Virtual Table via Web API

Read records from the virtual table through the Dataverse Web API. [src6]

```http
GET [Organization URI]/api/data/v9.2/new_externalproducts?$select=new_name,new_price,new_category&$filter=new_category eq 'Electronics'&$top=50
Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0
```

**Verify**: HTTP 200 response with `value` array containing external records. Response time should be <2s for co-located systems.

### 4. Perform CRUD Operations

Write operations work identically to native Dataverse tables. [src1, src7]

```http
POST [Organization URI]/api/data/v9.2/new_externalproducts
Content-Type: application/json

{
  "new_name": "Widget Pro",
  "new_price": 29.99,
  "new_category": "Electronics"
}
```

**Verify**: HTTP 204 response with `OData-EntityId` header. Confirm record exists in external source.

## Code Examples

### Python: Query F&O Virtual Entity via Dataverse Web API

```python
# Input:  Microsoft Entra app credentials, Dataverse environment URL
# Output: List of F&O customer records surfaced as virtual entities

import requests
from msal import ConfidentialClientApplication

# Authenticate to Dataverse
app = ConfidentialClientApplication(
    client_id="YOUR_APP_ID",
    client_credential="YOUR_CLIENT_SECRET",
    authority="https://login.microsoftonline.com/YOUR_TENANT_ID"
)
token = app.acquire_token_for_client(
    scopes=["https://YOUR_ORG.crm.dynamics.com/.default"]
)

headers = {
    "Authorization": f"Bearer {token['access_token']}",
    "OData-MaxVersion": "4.0",
    "OData-Version": "4.0",
    "Accept": "application/json",
    "Prefer": "odata.maxpagesize=100"  # Limit page size for performance
}

# Query F&O Customers virtual entity — use $select to avoid FK overhead
url = "https://YOUR_ORG.crm.dynamics.com/api/data/v9.2/mserp_custcustomerv3entities"
params = {
    "$select": "mserp_customeraccount,mserp_organizationname,mserp_customergroupid",
    "$filter": "mserp_customergroupid eq '10'",
    "$top": "50"
}

response = requests.get(url, headers=headers, params=params)
response.raise_for_status()

customers = response.json().get("value", [])
for c in customers:
    print(f"{c['mserp_customeraccount']}: {c['mserp_organizationname']}")
```

### C#/.NET: Create Record on Virtual Table

```csharp
// Input:  IOrganizationService from Dataverse SDK
// Output: GUID of created record in external system

using Microsoft.Xrm.Sdk;

// Virtual table CRUD works identically to native tables via SDK
var record = new Entity("new_externalproduct");
record["new_name"] = "Widget Pro Max";
record["new_price"] = new Money(49.99m);
record["new_category"] = "Electronics";

// Create passes through to external data source via data provider
Guid newId = service.Create(record);
Console.WriteLine($"Created virtual record: {newId}");

// Update works the same way
record.Id = newId;
record["new_price"] = new Money(44.99m);
service.Update(record);

// Delete
service.Delete("new_externalproduct", newId);
```

### PowerShell: Enable F&O Virtual Entity

```powershell
# Input:  Dataverse environment URL, F&O entity logical name
# Output: Virtual entity becomes visible in Dataverse

# Connect to Dataverse
Install-Module -Name Microsoft.Xrm.Data.PowerShell -Scope CurrentUser
$conn = Connect-CrmOnline -ServerUrl "https://YOUR_ORG.crm.dynamics.com"

# Find the F&O entity in the catalog
$catalog = Get-CrmRecords -conn $conn `
  -EntityLogicalName "mserp_finabortenvironmententity" `
  -FilterAttribute "mserp_physicalname" `
  -FilterOperator "eq" `
  -FilterValue "CustCustomerV3Entity"

# Enable visibility
$entityId = $catalog.CrmRecords[0].Id
Set-CrmRecord -conn $conn `
  -EntityLogicalName "mserp_finabortenvironmententity" `
  -Id $entityId `
  -Fields @{ "mserp_hasbeengenerated" = $true }
```

## Data Mapping

### OData EDM to Dataverse Type Gotchas

| Source Type (OData) | Target Type (Dataverse) | Transform | Gotcha |
|---|---|---|---|
| Edm.Guid | Unique Identifier | Direct | Must be used for primary key — no alternatives [src4] |
| Edm.Int32 | Whole Number | Direct | Cannot serve as primary key — common migration blocker [src4] |
| Edm.String (>4000 chars) | Multiple Lines of Text | Direct | Check max length constraints on external side |
| Edm.DateTimeOffset | Date and Time | Timezone conversion | Dataverse stores in UTC; external source may use local time [src4] |
| Edm.Decimal | Currency | Requires currency entity mapping | Currency lookup must exist in Dataverse |
| Nullable=False properties | Business Required | Must align | Mismatch causes silent save failures [src4] |

### Data Type Gotchas

- OData v4 provider returns ALL columns regardless of `$select` in Retrieve and RetrieveMultiple — the server-side projection is not applied. Performance optimization must happen at the external endpoint or via client-side column filtering. [src1]
- F&O virtual entities use the Dataverse company concept (cdm_companyid) — all cross-company queries require explicit company filtering or the CDSVirtualEntityAdapterService will default to the user's default company. [src2]
- Foreign key columns on virtual tables (prefixed with `_mshr_fk_`) trigger additional round-trips to resolve related records. Excluding these columns from queries can reduce response time by 50-80%. [src6]

## Error Handling & Failure Points

### Common Error Codes

| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| 429 | Too Many Requests (Dataverse throttling) | Exceeded 6,000 requests in 5-min window or 52 concurrent | Implement exponential backoff with Retry-After header [src5] |
| 429 (F&O) | Too Many Requests (F&O resource-based) | High CPU/memory utilization on F&O web servers | Reduce concurrency; check throttling prioritization settings [src5] |
| 400 | Bad Request | Nullable property mismatch or unsupported EDM type | Verify external field nullability matches Dataverse field requirement [src4] |
| InternalServerError | F&O timeout | Query too complex or F&O service unavailable | Increase timeout; simplify query; check F&O health [src6] |
| "Unable to determine the user in CDS" | Missing user mapping | S2S call used SYSTEM user or app without proper user context | Use organization context with appropriate application or end user that has F&O permissions [src2] |
| Entity not found | Virtual entity not visible | Entity not enabled in catalog | Check "Visible" checkbox in Available finance and operations entities [src3] |

### Failure Points in Production

- **Foreign key column expansion causes 429 throttling**: Large grids displaying virtual entity data with FK columns (e.g., Worker entity) trigger cascading retrievals that exhaust rate limits. Fix: `Always use $select to exclude _mshr_fk_ prefixed columns unless specifically needed`. [src6]
- **Cross-region latency spikes**: When Dataverse and F&O are in different Azure regions, virtual entity calls add 100-500ms overhead per call instead of <30ms. Fix: `Co-locate Dataverse and F&O in the same Azure region`. [src2]
- **Metadata refresh breaks consuming solutions**: After F&O entity schema changes, virtual entity metadata must be explicitly refreshed. Until refreshed, queries return stale column definitions or fail. Fix: `Set Refresh checkbox on entity in catalog after any F&O schema change`. [src3]
- **Portal user permissions misconfigured**: Power Apps portal users accessing F&O virtual entities with system administrator role causes security errors. Fix: `Assign CDSVirtualEntityAuthorizedPortalUser role; remove sysadmin and security admin roles`. [src2]
- **OData endpoint returns non-GUID primary key**: Integration silently fails or creates orphaned records when external source uses integer IDs. Fix: `Generate stable GUIDs from external IDs (e.g., deterministic UUID v5 from integer) in the data provider`. [src1, src4]

## Anti-Patterns

### Wrong: Including all columns in virtual table grid views

```http
// BAD — fetches all columns including FK navigation properties
GET /api/data/v9.2/mshr_hcmworkerbaseentities
// Returns ALL attributes including _mshr_fk_person_id_value, triggering
// cascading round-trips to F&O for each FK column. Causes throttling
// on datasets > 100 records.
```

### Correct: Use $select to exclude FK columns

```http
// GOOD — explicitly select only needed columns, excluding FK columns
GET /api/data/v9.2/mshr_hcmworkerbaseentities?$select=mshr_name,mshr_firstname,mshr_lastname,mshr_personnelnumber,mshr_partynumber
// 50-80% faster; avoids FK round-trips to F&O [src6]
```

### Wrong: Using virtual entities for bulk data migration

```csharp
// BAD — virtual entities are real-time federated; no bulk optimization
for (int i = 0; i < 50000; i++)
{
    var record = new Entity("mserp_vendvendortablev2entity");
    record["mserp_vendoraccountnumber"] = vendors[i].AccountNumber;
    service.Create(record);  // Each call = round-trip to F&O
}
// 50,000 sequential S2S calls → hours of runtime + likely throttled at 6,000/5min
```

### Correct: Use DMF/Data Import for bulk operations

```csharp
// GOOD — use Data Management Framework for bulk operations
// Virtual entities are for real-time federated access, not ETL
// DMF supports parallel processing with configurable batch sizes
// Use DMF REST API: POST /data/DataManagementDefinitionGroups/Microsoft.Dynamics.DataEntities.ImportFromPackage
```

### Wrong: Assuming auditing captures virtual entity changes

```
// BAD — relying on Dataverse audit to track changes to virtual entity records
// Auditing is NOT supported for virtual tables [src1]
// All change tracking must be implemented on the external system side
```

### Correct: Implement change tracking on the external system

```
// GOOD — use F&O data entity change tracking or external system audit logs
// For F&O: enable change tracking on the data entity in AOT
// For OData sources: implement your own audit trail in the external system
// For custom providers: log changes in the plug-in's Create/Update/Delete handlers
```

## Common Pitfalls

- **Not co-locating Dataverse and F&O**: Virtual entity calls traverse Azure regions, adding 100-500ms latency per call. Cumulative impact on grids displaying 50+ records is 5-25 seconds. Fix: `Always provision Dataverse and F&O in the same Azure region`. [src2]
- **Forgetting to refresh metadata after F&O updates**: After deploying F&O changes that add/modify entity columns, virtual entities in Dataverse still use cached schema. Fix: `Check the Refresh checkbox on each modified entity in the catalog; automate via CI/CD pipeline`. [src3]
- **Enabling all F&O entities as virtual**: Each visible virtual entity adds overhead to the Dataverse solution. Fix: `Only enable entities you actively need; disable unused ones by clearing the Visible checkbox`. [src3]
- **Expecting calculated columns to work**: Developers add calculated columns to virtual tables expecting Dataverse to compute them. They silently return null. Fix: `Implement calculations in the external system or create a computed view on the OData source side`. [src1]
- **Using virtual entities in Power BI without column optimization**: Power BI Desktop defaults to fetching all columns. With FK columns, this generates cascading queries that hit throttling limits. Fix: `Use Advanced Editor in Power Query to explicitly select only needed columns; exclude _mshr_fk_ prefixed columns`. [src6]
- **Portal security over-provisioning**: Assigning system administrator role to portal users accessing virtual entities triggers "Unable to determine the user" errors. Fix: `Use CDSVirtualEntityAuthorizedPortalUser role only; never assign sysadmin to portal-mapped users`. [src2]

## Diagnostic Commands

```bash
# Check if F&O virtual entities solution is installed (PowerShell)
Get-CrmRecords -conn $conn -EntityLogicalName "solution" -FilterAttribute "uniquename" -FilterOperator "like" -FilterValue "MicrosoftOperations%"

# List all visible F&O virtual entities
GET [Org URI]/api/data/v9.2/mserp_finabortenvironmententities?$filter=mserp_hasbeengenerated eq true&$select=mserp_physicalname,mserp_hasbeengenerated

# Test virtual entity access (simple retrieve)
GET [Org URI]/api/data/v9.2/mserp_custcustomerv3entities?$top=1&$select=mserp_customeraccount

# Check Dataverse API limits usage (via response headers)
# Look for: x-ms-ratelimit-burst-remaining-xrm-requests
# And: Retry-After header on 429 responses

# Verify F&O-Dataverse link status
# Power Platform admin center → Environments → [Your Env] → Details
# Finance and Operations URL should show as linked

# Monitor virtual entity performance (enable plug-in tracing)
# Settings → Administration → System Settings → Customization tab → Enable plug-in logging
# Then check: Settings → Plug-In Trace Log for errors from virtual entity operations
```

## Version History & Compatibility

| Feature | Release | Status | Notes |
|---|---|---|---|
| Virtual tables (OData v4 provider) | Dataverse 2017 | GA | Original release — read-only |
| CRUD support for OData v4 provider | Dataverse 2020 Wave 2 | GA | Full Create, Update, Delete added [src1] |
| Custom data provider CRUD | Dataverse 2020 Wave 2 | GA | Plug-in registration for all 5 operations [src8] |
| F&O virtual entities | F&O 10.0.12 / Dataverse service update 189 | GA | Full CRUD for F&O OData entities [src2] |
| Azure Cosmos DB provider | 2021 | GA | Available from Azure Marketplace [src1] |
| Virtual Table Creation Wizard | 2024 Wave 2 | Preview | No-code creation for SharePoint and SQL sources |
| User-based API limits removed for F&O | 10.0.36 | GA | Optional user-based limits disabled; resource-based remain [src5] |

### Deprecation Policy

Microsoft does not formally deprecate virtual entity providers, but the underlying Dataverse SDK and OData standards evolve. Virtual entities created with earlier SDK versions continue to function. The F&O virtual entity provider follows F&O's standard support lifecycle — minimum 2 years of support per major version. [src2, src5]

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Real-time federated access to external data without duplication | Need auditing, search, or calculated columns on external data | Dual Write or DMF to replicate into native Dataverse tables |
| Power Apps/Power Automate needs to read/write F&O entities | Bulk data migration (>10K records) | Data Management Framework or Azure Synapse Link |
| Building cross-app experiences (CE + F&O) without data sync lag | Need charts, dashboards, or advanced visualizations | Replicate data into Dataverse or use Power BI DirectQuery |
| Low-volume real-time CRUD (<1K operations/day) | Need field-level security or user-owned record filtering | Native Dataverse tables with proper security model |
| Prototyping integrations before committing to Dual Write | High-concurrency scenarios (>50 concurrent users querying same virtual entity) | Dual Write for replicated low-latency access |
| Portal access to F&O data with user-context security | Offline-capable mobile apps | Replicate to native tables for offline sync |

## Important Caveats

- Virtual entities return all columns on Retrieve/RetrieveMultiple regardless of `$select` — this is a known platform behavior, not a bug. Performance optimization must happen at the external endpoint or via narrow client-side projections. [src1]
- F&O virtual entity exemption from service protection API limits applies ONLY when Power Platform integration is enabled. Without integration, F&O endpoints enforce full throttling. [src5]
- The Dataverse service protection limits (6,000 requests/5 min, 52 concurrent) still apply to the Dataverse side of virtual entity calls — the exemption only covers the F&O endpoint. [src5]
- Security is binary (org-wide on/off) — there is no way to restrict virtual entity access to specific records or fields within Dataverse. Row-level security depends entirely on the external system's own authorization. [src1]
- Virtual table lookup columns in grid views cannot be filtered or sorted — this is a permanent platform limitation. [src1]

## Related Units

- [Dynamics 365 Dual Write Capabilities](/business/erp-integration/dynamics-365-dual-write-capabilities/2026) — bidirectional data replication alternative
- [Dynamics 365 Data Management Framework](/business/erp-integration/dynamics-365-dmf-import-export/2026) — bulk data import/export for high-volume ETL
- [Dynamics 365 Dataverse API Capabilities](/business/erp-integration/dynamics-365-dataverse-api-capabilities/2026) — direct Dataverse CRUD without federation
- [Dynamics 365 Web API Capabilities](/business/erp-integration/dynamics-365-web-api-capabilities/2026) — F&O OData endpoint direct access
