Skip to main content

Tables

A Table in the AOT represents a database table in D365 F&O. Each table inherits from the Common system class, providing a standard interface for record manipulation, validation, and event handling. When a record is loaded from the database it is held in a table buffer whose fields map directly to the columns of the underlying SQL table.

Tables are the foundation of the data model — forms, data entities, views, queries, and reports all consume them.


Table Architecture Overview

D365 F&O Table Architecture — table types and Common inheritance


Inherited Methods from Common

Every table inherits from the Common class. These virtual methods are called by the runtime at specific points during the record lifecycle. Override them on individual tables to inject business logic. See Code Examples for implementation patterns.

Data Manipulation Methods

MethodDescription
insert()Called when a new record is written to the database. Override to add pre/post-insert logic. The super() call performs the actual SQL INSERT.
update()Called when an existing record is saved. The buffer must be selected with forupdate. Use orig() to compare old vs new values.
delete()Called when a record is removed. Override to clean up child records or enforce business rules.
doInsert()Executes the INSERT directly, bypassing the overridden insert(), all events, and database logging.
doUpdate()Executes the UPDATE directly, bypassing the overridden update(), all events, and database logging.
doDelete()Executes the DELETE directly, bypassing the overridden delete(), all events, and database logging.
danger

doInsert(), doUpdate(), and doDelete() skip all table-level business logic, events, database logging, and alert rules. Use only when the bypass is intentional (e.g., data migration, bulk data fixes).

Initialisation and Reset

MethodDescription
initValue()Called when a new record buffer is created in a form context (user clicks "New"). Sets default field values. Not called during direct X++ inserts unless explicitly invoked.
clear()Resets every field in the buffer to its default value (zero, empty string, or first enum value). RecId becomes 0. Useful when reusing a buffer to insert multiple records in a loop.

Validation Methods

MethodDescription
validateWrite()Called automatically before insert() and update(). Returns false to cancel the write. Override for cross-field validation.
validateField(FieldId)Called when a field value changes on a form. Validates individual field values immediately as the user enters them.
validateDelete()Called before a record is deleted from a form. Returns false to cancel the deletion.

Field Change and Record Refresh

MethodDescription
modifiedField(FieldId)Called after a field value changes on a form. Use for cascading updates (e.g., looking up a name when an account number is entered). Does not return a boolean — cannot cancel the change.
reread()Re-reads the current record from the database into the buffer, discarding in-memory changes. Important for concurrency scenarios where another process may have modified the record.

Common Static Patterns

While not inherited from Common, it is standard practice to implement find() and exist() as static methods on every table. See Code Examples for the full pattern.


System Fields

Every table in D365 F&O has a set of system-managed fields that are automatically present on all records. These fields are not visible in the AOT field list but exist on every table buffer.

RecId

A 64-bit integer that uniquely identifies each record across the entire system. RecId values are assigned automatically by the kernel during insert and are globally unique — no two records in the system share the same RecId, regardless of table. This field is always indexed and is the default join/reference key when no other key is specified.

RecVersion

An integer used for optimistic concurrency control (OCC). Each time a record is updated, RecVersion is incremented. When an update is attempted, the runtime checks that RecVersion in the buffer matches RecVersion in the database. If another process has modified the record, the versions will differ and the update will throw an UpdateConflict exception. This prevents lost updates in multi-user scenarios.

The OccEnabled property on the table controls whether this check is active. When set to Yes (the default for most tables), the runtime enforces version checking. See the Code Examples section for handling UpdateConflict.

Partition

A system field that was historically used to partition data between different logical partitions. Partitioning has been deprecated in recent versions of D365 F&O, but the field still exists on all tables. In current deployments there is a single partition.

DataAreaId

Identifies the company (legal entity) that owns the record. When SaveDataPerCompany is set to Yes on the table properties, every query is automatically filtered by the current company context. Records from other companies are invisible unless you explicitly use crossCompany in a query or change company context with changecompany.

Tables with SaveDataPerCompany set to No are shared across all companies (e.g., global configuration tables).

Audit Tracking Fields

These fields are not present by default. They are created automatically when the corresponding table property is set to Yes:

PropertyField CreatedPurpose
CreatedDateTimeCreatedDateTimeUTC timestamp of when the record was first inserted.
CreatedByCreatedByUser ID of the user who created the record.
CreatedTransactionIdCreatedTransactionIdTransaction ID of the insert operation.
ModifiedDateTimeModifiedDateTimeUTC timestamp of the last update to the record.
ModifiedByModifiedByUser ID of the user who last modified the record.
ModifiedTransactionIdModifiedTransactionIdTransaction ID of the last update operation.
tip

Enable CreatedDateTime and ModifiedDateTime on any table that requires audit trails, data synchronisation timestamps, or change tracking. These are populated automatically by the kernel with no additional code required.


Valid Time State Tables

The Valid Time State framework stores date-effective records — rows valid only within a specific date range. Used for exchange rates, employee positions, pricing tiers, and benefit enrollments.

Setup

  1. Set ValidTimeStateFieldType to Date or UtcDateTime — the system creates ValidFrom and ValidTo fields automatically.
  2. Create a unique index over the business key fields plus ValidFrom, and set ValidTimeStateKey to Yes.
  3. Set ValidTimeStateMode on the index:
    • NoGap — the system enforces no gaps between consecutive records for the same key, auto-adjusting adjacent records on insert.
    • Gap — gaps between validity periods are allowed.

Queries are automatically filtered to the current date/time unless overridden with validTimeState(). See Code Examples for query patterns.


Table Types

The TableType property determines where and how data is stored.

Regular Tables

The default type — persistent SQL Server tables. Data survives restarts, is backed up, and visible to all sessions (subject to company/security filtering). Supports the full feature set: indexes, relations, delete actions, change tracking, database logging, full-text search, views, queries, and data entities. The vast majority of tables are Regular.

InMemory Tables

Data stored entirely in AOS memory. Exists only for the duration of the variable's scope. No SQL persistence, no indexes, no transaction support. Two variables of the same InMemory type each have independent data sets. Use for small data sets (under a few hundred rows) such as form display buffers or passing structured data between methods.

TempDB Tables

Temporary SQL Server tables created in tempdb on demand. SQL-backed (supports indexes, joins, set-based operations) but session-scoped and automatically cleaned up. No cross-session visibility. Use for staging data, intermediate computations, report data sources, or large derived data sets.

tip

InMemory vs TempDB: Use InMemory for small, simple data sets that don't need joins or set-based operations. Use TempDB for larger data sets, when you need indexes, or when joining temporary data with persistent tables.

See Code Examples for usage patterns with each table type.


Properties

54/54 properties
PropertyDisplay NameTypeDescription
Inherited from base
NameNameStringThe name of the element.
LabelLabelStringLabel containing a user-friendly name of the table.
SingularLabelSingular LabelStringLabel used to describe one row in the table (e.g. "Customer" vs "Customers").
DeveloperDocumentationDeveloper DocumentationStringText explaining the table to developers.
Table-specific
ExtendsExtendsStringBase table participating in inheritance.
AbstractAbstractNoYesWhether the table is abstract or concrete. Values: No (0), Yes (1).
SupportInheritanceSupport InheritanceNoYesWhether this table can support inheritance. Values: No (0), Yes (1).
InstanceRelationTypeInstance Relation TypeStringInstance type of the inheritance hierarchy for the current buffer.
TableTypeTable TypeTableTypeSelect the type of the table. Values: Regular (0), InMemory (1), TempDB (2).
TableContentsTable ContentsTableContentsSelect which type of data the table contains. Values: NotSpecified (0), BaseData (1), DefaultData (2), BaseDefaultData (3).
SystemTableSystem TableNoYesTreat the table as a system table. Values: No (0), Yes (1).
IsKernelTableIs Kernel TableBooleanTable is defined by the runtime framework.
Inherited from base
TableGroupTable GroupTableGroupSelect which group the table is part of. Values: Miscellaneous (0), Parameter (1), Group (2), Main (3), Transaction (4), WorksheetHeader (5), WorksheetLine (6), Framework (7), Reference (8), Worksheet (9), TransactionHeader (10), TransactionLine (11), Staging (12).
EntityRelationshipTypeEntity Relationship TypeEntityRelationshipTypeDistinguishes entity tables from relationship tables. Values: Entity (0), Relationship (1).
VisibleVisibleNoYesDetermines whether controls bound to the table will be visible on a form. Values: No (0), Yes (1).
IsObsoleteIs ObsoleteNoYesDetermines whether the element is deprecated. Values: No (0), Yes (1).
ConfigurationKeyConfiguration KeyStringThe configuration key assigned to the item.
FormRefForm RefStringMenu item identifying the form to use when the table is referenced in "Go to table" or "View Details" operations.
ListPageRefList Page RefStringMenu item designating the form to use to show lists of records from this table.
ReportRefReport RefStringMenu item identifying the report to use when the table is referenced.
PreviewPartRefPreview Part RefStringMenu item designating the form to use to display previews of records from this table.
TitleField1Title Field1StringValues of this field are displayed in form titles to identify the current record.
TitleField2Title Field2StringValues of this field are displayed in form titles to identify the current record (secondary).
Table-specific
PrimaryIndexPrimary IndexStringSelect which index is the primary index (used for optimization).
ClusteredIndexClustered IndexStringSelect which index is the clustered index (used for optimization).
ReplacementKeyReplacement KeyStringSelect the natural key index.
CreateRecIdIndexCreate Rec Id IndexNoYesCreate an index on the RecId field automatically. Values: No (0), Yes (1).
CacheLookupCache LookupRecordCacheLevelCache select results if the WHERE expression selects a unique record. Values: None (0), NotInTTS (1), Found (2), FoundAndEmpty (3), EntireTable (4).
AosAuthorizationAOS AuthorizationAosAuthorizationWhat authorization setting does a table have? Values: None (0), CreateDelete (1), UpdateDelete (2), CreateUpdateDelete (3), CreateReadUpdateDelete (4), Read (5).
SaveDataPerCompanySave Data Per CompanyNoYesSave the data per company (legal entity). Values: No (0), Yes (1).
SaveDataPerPartitionSave Data Per PartitionNoYesSave the data per partition. Values: No (0), Yes (1).
OccEnabledOCC EnabledNoYesSpecifies whether optimistic concurrency control is enabled on this table. Values: No (0), Yes (1).
ValidTimeStateFieldTypeValid Time State Field TypeValidTimeStateFieldTypeThe type of the field to be used for a valid time state table. Values: None (0), Date (1), UtcDateTime (2).
ModifiedDateTimeModified Date TimeNoYesAuto-generate a field for the last UTC datetime on which the record was modified. Values: No (0), Yes (1).
ModifiedByModified ByNoYesAuto-generate a field containing the name of the user who last modified the record. Values: No (0), Yes (1).
ModifiedTransactionIdModified Transaction IdNoYesAuto-generate a field for the transaction in which the record was last modified. Values: No (0), Yes (1).
CreatedDateTimeCreated Date TimeNoYesAuto-generate a field for the UTC datetime on which the record was created. Values: No (0), Yes (1).
CreatedByCreated ByNoYesAuto-generate a field for the user who created the record. Values: No (0), Yes (1).
CreatedTransactionIdCreated Transaction IdNoYesAuto-generate a field for the transaction in which the record was created. Values: No (0), Yes (1).
StorageModeStorage ModeStorageModeSelect the storage mode of the table. Values: Disk (0), InMemory (1).
DurabilityDurabilityDurabilitySelect the durability of the table. Values: Schema (0), SchemaAndData (1).
DataSharingTypeData Sharing TypeSysDataSharingTypeSpecifies the type of data sharing this table supports. Values: None (0), Duplicate (1), Single (2).
AllowOverrideAllow OverrideNoYesAllow record override when single data sharing is enabled. Values: No (0), Yes (1).
AllowChangeTrackingAllow Change TrackingNoYesAllow changes of the table to be tracked. Values: No (0), Yes (1).
AllowRowVersionChangeTrackingAllow Row Version Change TrackingNoYesAllow row version change tracking for the table. Values: No (0), Yes (1).
DisableLockEscalationDisable Lock EscalationNoYesDisable lock escalation for the table. Values: No (0), Yes (1).
DisableDatabaseLoggingDisable Database LoggingNoYesDisable database logging for the table. Values: No (0), Yes (1).
AllowArchivalAllow ArchivalNoYesAllow the table to participate in archiving functionality. Values: No (0), Yes (1).
AllowRetentionAllow RetentionNoYesAllow the table to participate in retention functionality. Values: No (0), Yes (1).
ModulesModulesStringDefines the application module under which this table will be categorized in the Common Data Model.
Inherited from base
CountryRegionCodesCountry Region CodesStringComma-separated list of ISO country codes where this table is valid.
CountryRegionContextFieldCountry Region Context FieldStringSpecifies the field used to identify the country context.
OperationalDomainOperational DomainOperationalDomainOperational domain responsible for publishing the data. Values: NotSpecified (0), Shared (1), Company (2), Local (3).
SubscriberAccessLevelSubscriber Access LevelAccessGrantMaximum access level granted to subscribers of the operational domain.