Technical6 min read

Computed columns in D365 F&O data entities (vs virtual fields)

In a D365 F&O data entity, a computed column is a SQL column generated by a static X++ method. When to use it over a virtual field, code and pitfalls.

The short answer

In Dynamics 365 Finance & Operations, a data entity computed column is an unmapped field whose value SQL Server calculates. You create it with an "Unmapped" field whose IsComputedField property is Yes, and a static X++ method that returns the SQL expression. That method is only called when the database is synchronised: at run time, SQL computes the value directly in the entity view.

The other option is the virtual field (IsComputedField = No): its value is calculated in X++, row by row, for example in postLoad. Microsoft recommends computed columns where possible, because they are computed at the SQL Server level. Virtual fields support neither search nor filtering.

Note: if you are looking for a "calculated field" in the sense of a formula on a form, that is usually a display method; this article covers data entities, used for import/export, OData and integrations.

Computed column or virtual field: how to choose?

  • Computed column: value produced by a computed column of the SQL view; read directly from the view; ideal for reads and exports; filterable.
  • Virtual field: not persisted, read and written by X++ code; reserve it for values that cannot be expressed in SQL; no search or filter.
  • On writes, both go through X++ (for example mapEntityToDataSource) that splits the incoming value into the real fields of the data sources.

Impact on export performance: Microsoft advises against postLoad, which forces the export through the staging table so the method can be called for each row. Prefer a computed column when SQL can produce the value.

Creating a computed column step by step

The Microsoft Learn example adds a NameAndAddress field to the FMCustomerEntity entity, concatenating name and address:

  1. In the entity designer, right-click Fields > New > String Unmapped Field; name it NameAndAddress.
  2. Leave IsComputedField set to Yes and set the method property (DataEntityView Method / ComputedFieldMethod) to the name of the static method.
  3. Create that static method; it builds the SQL expression with the SysComputedColumn class (returnField, returnLiteral, addList, cast…).
  4. Rebuild, then synchronise the database: the column is created in the entity's SQL view.

Simplified version of the method:

private static str formatNameAndAddress()
{
    DataEntityName dataEntityName = tablestr(FMCustomerEntity);
    List           fieldList = new List(types::String);

    fieldList.addEnd(SysComputedColumn::returnField(dataEntityName,
        identifierstr(FMCustomer), fieldstr(FMCustomer, FirstName)));
    fieldList.addEnd(SysComputedColumn::returnLiteral(" "));
    fieldList.addEnd(SysComputedColumn::returnField(dataEntityName,
        identifierstr(FMCustomer), fieldstr(FMCustomer, LastName)));
    fieldList.addEnd(SysComputedColumn::returnLiteral("; "));
    fieldList.addEnd(SysComputedColumn::returnField(dataEntityName,
        identifierstr(FMAddressTable), fieldstr(FMAddressTable, City)));

    return SysComputedColumn::addList(fieldList);
}

Tip from Microsoft: if synchronisation fails, first work out the SQL expression in SQL Server Management Studio, then translate it into X++.

And the virtual field?

Create an Unmapped field with IsComputedField = No, then override postLoad to compute the value on read:

public void postLoad()
{
    super();
    // Virtual field: "LastName, FirstName"
    this.FullName = this.LastName + ", " + this.FirstName;
}

To accept this value on write (for example an external system sending "LastName, FirstName"), override mapEntityToDataSource and split the value into the fields of the relevant data source.

Common mistakes

  • Forgetting to synchronise the database after building: the column does not exist in the view.
  • Writing a join inside the SQL expression: Microsoft recommends adding the required table as a data source of the entity instead, otherwise SQL computes row by row.
  • Letting the method throw an exception: synchronisation catches it, sets the column to NULL and only logs a warning. Check configuration keys inside the method.
  • Using postLoad (virtual field) for simple formatting: the export goes through the staging table and slows down.
  • Mixing types without a cast: use SysComputedColumn::cast for concatenated numeric or date fields.

Going further

To create the entity itself and export it, read create a data entity and export it with DMF. Skalp AI generates this kind of development (entity, computed columns, unit tests), delivered to your Azure DevOps and validated by your IT lead: see data entities and DMF packages, the bigger picture in building X++ without a consultant in 2026 and the Basic, Pro and Max plans.

Sources

Frequently asked questions

Is a computed column stored in the database?

No. It is a computed column of the entity's SQL view. On write, X++ code splits the value into the real fields of the data sources, which are stored.

Can you filter on a virtual field?

No, search and filtering are not supported on virtual fields. Use a computed column if you need to filter.

Why does my computed column return NULL?

The method generating the SQL expression probably threw an exception during synchronisation: the column is then set to NULL with only a warning. Check the synchronisation log and configuration keys.

Ready to transform your D365?

Join the CIOs who develop their D365 tickets in 1h for 1 credit (≈ €400 on Basic, €200 on Pro).