6.1 Table Design & Extension
Key Takeaways
- Dynamics 365 Finance and Operations supports three distinct table types: Regular tables (persisted in Azure SQL Database), InMemory tables (cached in client/AOS memory and spilled to local disk beyond ~128 KB), and TempDB tables (physical temporary tables in SQL Server tempdb supporting joins and set-based operations).
- Extended Data Types (EDTs) encapsulate primitive data types with centralized labels, help text, display formats, and array elements, while Base Enums define discrete integer-backed value sets that can be declared extensible (IsExtensible = True) or non-extensible.
- When a Base Enum is marked as extensible (IsExtensible = True), the compiler generates internal hash IDs for enum values; X++ code must strictly compare enum values using symbol literals rather than hardcoded integers.
- Table relations govern referential integrity and UI lookups, spanning Normal relations, Field Fixed relations (filtering source table records), Related Field Fixed relations (filtering target table records), and Surrogate Foreign Key relations linked via 64-bit RecId.
- Table extensions permit non-intrusive additions—including custom fields, field groups, non-clustered indexes, and new relations—while enforcing strict immutability on base tables, prohibiting the deletion of standard fields, modification of existing data types, or alteration of ClusteredIndex and PrimaryIndex.
6.1 Table Design & Extension
Quick Answer: Tables form the foundational physical data layer in Dynamics 365 Finance and Operations (F&O). Tables are categorized into three types: Regular (physical tables in Azure SQL Database), InMemory (process memory temporary tables, spilling to disk files beyond 128 KB), and TempDB (physical temporary tables created inside SQL Server
tempdb, supporting joins, transactions, and set-based operations). Data types are encapsulated through Extended Data Types (EDTs) and Base Enums. When Base Enums haveIsExtensible = True, developers must never compare them against hardcoded integer values. Table relations enforce referential integrity across Normal, Field Fixed, Related Field Fixed, and Surrogate Foreign Key relationships. Through Table Extensions, developers can add new fields, field groups, non-clustered indexes, and relations to standard tables, but cannot delete standard fields, modify existing field data types, reduce string lengths, or alter theClusteredIndexorPrimaryIndex.
1. Table Types & Persistence Architecture
In Dynamics 365 Finance and Operations, every table declared in the Application Object Tree (AOT) possesses a TableType property that dictates how the Application Object Server (AOS) and the underlying database engine manage storage, memory caching, indexing, and transactional boundaries.
Architectural Comparison of Table Types
| Architectural Dimension | Regular Table | InMemory Table | TempDB Table |
|---|---|---|---|
| Physical Storage Location | Azure SQL Database (clustered column/index on disk) | Client or AOS process memory; spills to disk temporary files beyond ~128 KB | SQL Server tempdb database as a physical temporary table (t12345_...) |
| Scope & Lifetime | Permanent persistence until explicitly deleted by business logic | In-memory buffer variable scope; dropped when record variable goes out of scope | Current user/batch AOS session; dropped when table buffer variable loses scope |
| Direct SQL Joins with Regular Tables | Fully supported across all standard SELECT queries | Unsupported; joining InMemory with Regular pulls Regular rows to AOS memory | Fully supported; executes natively inside SQL Server query optimizer |
| Set-Based SQL Operations | insert_recordset, update_recordset, delete_from fully supported | Executed row-by-row in AOS memory; no SQL set-based acceleration | Fully supported (insert_recordset, update_recordset, delete_from) |
| Transaction (TTS) Rollback Support | Fully rolled back upon ttsabort or unhandled exceptions | No rollback; memory mutations persist even if transaction aborts | Fully rolled back; participates in standard SQL transaction log rollbacks |
| Foreign Keys & Secondary Indexes | PrimaryIndex, AlternateKey, NonClustered indexes, Foreign Keys | Non-clustered indexes supported in memory; no foreign key constraints | Non-clustered indexes supported in tempdb; no persistent foreign keys |
| Typical Enterprise Use Case | Master data, transactional documents, general ledger journals | Lightweight UI dialog dropdowns, legacy reporting parameter caches | High-volume staging, complex multi-table data processing, SSRS RDP processing |
Technical Deep Dive: TempDB vs. InMemory
Prior to Dynamics AX 2012, temporary tables operated strictly in memory (the InMemory type). When an InMemory table grows beyond approximately 128 KB, the runtime writes temporary binary files (.tmp) to the local disk of the executing tier (AOS or client). This disk thrashing degrades performance for large datasets. Furthermore, queries that join an InMemory table with a Regular database table cannot execute set-based SQL joins; instead, the AOS issues queries to retrieve candidate records from the SQL database and evaluates joins row-by-row in application memory.
In contrast, TempDB tables instantiate a physical temporary table inside the database server's dedicated tempdb catalog. Because the table exists inside SQL Server:
- The SQL query optimizer can join
TempDBtables with standard transactional tables (such asCustTableorSalesLine) using hash joins, nested loops, or merge joins. - Set-based operations (
insert_recordset) execute entirely within the database engine without pushing record buffers across the network to the AOS tier. - TempDB tables participate in
ttsbeginandttcommittransactional scopes. If an exception triggersttsabort, operations performed on theTempDBtable are rolled back in the SQL transaction log.
// Instantiating and utilizing a TempDB table for set-based processing
TmpAccountSum tmpAccountSum;
ttsbegin;
// Perform set-based bulk insert directly in SQL tempdb
insert_recordset tmpAccountSum (AccountNum, BalanceAmount)
select AccountNum, sum(AmountMST) from custTrans
group by AccountNum;
// Update or join directly with Regular tables
CustTable custTable;
while select tmpAccountSum
join custTable
where custTable.AccountNum == tmpAccountSum.AccountNum
{
// High-performance joined cursor
}
ttscommit;
2. Fields, Extended Data Types (EDTs) & Base Enums
Dynamics 365 F&O enforces strong data typing and metadata-driven encapsulation. Rather than binding database columns directly to primitive SQL primitives (such as VARCHAR(20) or DECIMAL(18,2)), the application abstracts data through Extended Data Types (EDTs) and Base Enums.
Extended Data Types (EDTs)
An EDT is an encapsulation of a primitive type (String, Integer, Int64, Real, Date, UtcDateTime, Guid) that enriches the primitive with business semantics:
- Inheritance (
ExtendsProperty): EDTs support single inheritance. For example,CustAccountextendsAccountNum, which in turn extendsSysGroup. A sub-type inherits the label, help text, display length, string size, and formatting of its ancestor unless explicitly overridden. - Encapsulated Metadata: An EDT defines user-interface properties including
Label,HelpText,DisplayLength,StringSize,NoOfDecimals, and alignment. - EDT Relations (Legacy vs. Modern): In legacy versions (AX 2012 and earlier), foreign key relationships could be defined directly on EDTs. In modern Dynamics 365 Finance and Operations, EDT relations are deprecated and obsolete. All relational constraints and lookups must be defined on table-level relations.
Base Enums: Extensible vs. Non-Extensible
A Base Enum is a collection of named constant values backed by an underlying 32-bit integer in the SQL database.
- Non-Extensible Base Enums (
IsExtensible = False):- The enum definition is closed. Developers cannot add new enum values via extensions.
- Enum values have deterministic, sequential integer assignments defined directly in metadata (e.g.,
Value0 = 0,Value1 = 1,Value2 = 2).
- Extensible Base Enums (
IsExtensible = True):- Developers can create an Enum Extension in a separate package and append custom enum values.
- The Hash ID Mechanism: Because multiple independent extensions (from different ISVs or partners) might add enum values, Microsoft eliminated static integer numbering for extensible enums. When an extensible enum compiles, the build system generates an internal 32-bit hash value for each extended element.
[!WARNING] Critical Exam Rule: Never Compare Extensible Enums to Hardcoded Integers In X++, writing
if (salesTable.SalesStatus == 1)is a severe anti-pattern that fails or causes unpredictable bugs when dealing with extensible enums. Because extended enum elements receive non-sequential system-generated integer IDs, developers must always use the symbolic enum literal:if (salesTable.SalesStatus == SalesStatus::Backorder).
3. Field Groups & UI Automation
Field groups organize table columns into functional collections that simplify form design, report generation, and data entity mapping.
System Field Groups
AutoReport: Specifies the default columns included when a user generates an ad-hoc auto-report from a grid.AutoLookup: Governs the automatic dropdown lookup grid rendered when a user clicks a lookup control on a form, provided no custom lookup form or lookup method overrides the control. Columns placed inAutoLookupappear sequentially in the lookup grid.AutoBrowse: Used by internal navigation tools to identify primary browse columns.
Custom Field Groups and Dynamic Extension Propagation
When designing forms, developers drag a table's Field Group onto a form design pattern (such as a FastTab or Details group) rather than binding individual fields. When a developer subsequently extends the table in a separate model and adds custom fields to that Field Group, the new fields automatically propagate to all forms and data entities consuming that Field Group without requiring any modification to the form extension metadata.
4. Index Architecture & Clustered vs. Non-Clustered Indexes
Indexes accelerate data retrieval, enforce business uniqueness, and dictate physical disk layout in Azure SQL Database.
Index Types and Properties
PrimaryIndex: The unique index designated as the primary identifier of table rows. It is referenced by foreign keys and table relation definitions.AlternateKey: A unique index (AllowDuplicates = No) representing the natural business key of the record (for example,AccountNumonCustTableorItemIdonInventTable). When a table uses a Surrogate Key architecture, theAlternateKeyserves as the human-readable replacement key.ClusteredIndex: Dictates the physical sort order of rows stored on SQL Server data pages. In Dynamics 365 F&O, theClusteredIndexdefaults to the surrogate keyRecId(RecIdIndex). Microsoft strongly advises against modifying the clustered index of standard tables because altering disk layout across multi-million row transactional tables degrades high-concurrency inserts.NonClusteredIndexes: Secondary search structures containing index key columns and row locators pointing to the clustered index. Can be unique (AllowDuplicates = No) or non-unique (AllowDuplicates = Yes).
Covering Indexes with IncludedColumnList
To eliminate expensive SQL Server bookmark lookups (Key Lookups) during read operations, developers configure covering indexes. By specifying columns in the index's IncludedColumnList property, the database engine stores non-key payload data directly at the leaf level of the B-tree index without incorporating those columns into the index key itself. This keeps the index key narrow and compact while satisfying SELECT queries entirely from the index.
5. Table Relations & Referential Integrity
Table relations establish logical connections between tables, enforce referential integrity constraints, and drive automatic lookup behaviors.
Classification of Table Relations
Table Relations Architecture
├── Normal Relation (Source.Field == Target.Field)
├── Field Fixed Relation (Source.Type == FixedConstant)
├── Related Field Fixed Rel (Target.Type == FixedConstant)
└── Foreign Key Relation (Surrogate RecId -> Target AlternateKey)
- Normal Relation:
- A standard equi-join matching a field in the source table to a field in the target table.
- Example:
CustTrans.AccountNum == CustTable.AccountNum.
- Field Fixed Relation:
- Filters records based on a fixed integer or enum condition applied to the source table.
- Example: On a polymorphic credit table,
CreditTable.AccountType == AccountType::Customerrestricts the relation so that foreign keys only validate when the current record represents a customer.
- Related Field Fixed Relation:
- Filters records based on a fixed integer or enum condition applied to the target (related) table.
- Example: In document handling (
DocuRef), the relation toCustTablespecifiesDocuRef.RefTableId == tableNum(CustTable). The relation only links to target records where the target table identifier matchesCustTable.
- Surrogate Foreign Key Relations:
- Relates a 64-bit integer (
RecId) foreign key field in the child table to theRecIdprimary key of the parent table. - Bound to an Alternate Key on the parent table. At runtime, the client framework utilizes the parent table's
ReplacementFieldGroupto display human-readable business values (such asAccountNum) in UI controls while storing the surrogateRecIdin the database.
- Relates a 64-bit integer (
6. Table Extensions & Immutability Boundaries
In Dynamics 365 Finance and Operations, over-layering is deprecated. All customizations must be implemented via Extensions. When extending a standard table (e.g., creating CustTable.Extension), developers must understand what properties are modifiable versus which base properties are strictly immutable.
Extension Capabilities vs. Immutability Rules
| Action / Property | Extensible? | Implementation Rules & System Behavior |
|---|---|---|
| Add Custom Fields | Yes | Prefix field names with custom model prefix (e.g., ABC_TrackingCode) to prevent naming collisions. |
| Add Custom Field Groups | Yes | Custom field groups can be created; standard or custom fields can be placed inside them. |
| Modify Existing Field Groups | Yes | Developers can append custom fields or standard unassigned fields to existing standard field groups. |
| Add New Indexes | Yes | Developers can add new non-clustered indexes (AllowDuplicates = Yes or No). |
| Add New Table Relations | Yes | Custom Normal, Field Fixed, and Foreign Key relations can be added to standard tables. |
| Delete Standard Fields | NO | Immutable. Standard fields cannot be deleted or hidden at the table metadata level. |
| Modify Existing Field Types | NO | Immutable. You cannot change a standard field from String to Integer, or swap its underlying EDT. |
| Reduce Base Field String Size | NO | Immutable. You cannot decrease the length of a standard string field (would truncate standard data). |
| Change TableType Property | NO | Immutable. You cannot convert a Regular table to TempDB or InMemory via extension. |
| Modify Standard Indexes | NO | Immutable. You cannot delete standard indexes, remove fields from them, or change their uniqueness. |
| Change Primary or Clustered Index | NO | Immutable. The base table's PrimaryIndex and ClusteredIndex properties cannot be changed. |
| Enable Tracking Properties | Yes | You can switch CreatedDateTime, ModifiedDateTime, CreatedBy, ModifiedBy from No to Yes. |
7. Scenario Walk-Through: Extending CustTable with Custom Logistics Tracking
Scenario Description
An enterprise shipping company requires adding a custom carrier tracking account (ABC_CarrierAccountNum) and an automated delivery confirmation requirement flag (ABC_RequireSignature) to the standard CustTable. In addition, queries filtering by carrier account must execute with sub-second response times, and the fields must automatically render on customer lookup forms.
Step-by-Step Implementation Flow
- Create Extended Data Types:
- In Visual Studio, create EDT
ABC_CarrierAccountNumextendingAccountNumwith Label "Carrier Account Number". - Create EDT
ABC_RequireSignatureextendingNoYesIdwith Label "Require Delivery Signature".
- In Visual Studio, create EDT
- Create Table Extension (
CustTable.MyModelExtension):- Right-click
CustTablein the AOT and select Create extension. - Under the
Fieldsnode, dragABC_CarrierAccountNumandABC_RequireSignature.
- Right-click
- Enable Database Tracking Flags:
- In the extension properties, verify that
ModifiedDateTimeandModifiedByare set toYesto audit changes.
- In the extension properties, verify that
- Add Field to Standard Field Group:
- Expand
Field Groups > AutoLookupand dragABC_CarrierAccountNuminto the group. This ensures the carrier account appears in standard customer dropdowns.
- Expand
- Create Covering Non-Clustered Index:
- Expand
Indexes, create indexABC_CarrierAccountIdxwithAllowDuplicates = Yes. - Add
ABC_CarrierAccountNumandDataAreaIdto the index keys. - Add
ABC_RequireSignaturetoIncludedColumnList. This creates a covering index that resolves carrier verification queries without triggering SQL Server bookmark lookups.
- Expand
- Build and Synchronize:
- Compile the project and perform a full database synchronization to generate the schema additions in Azure SQL Database.
8. Real-World Exam Traps: Table Design & Extensions
[!WARNING] Exam Trap 1: Attempting to Join InMemory Tables with Regular Tables in SQL A common question presents a query joining a temporary table to
SalesLineand asks why performance is catastrophic or why an error occurs. If the temporary table isInMemory, SQL Server cannot join it directly with regular tables; the AOS executes row-by-row lookups. The correct architectural remedy is converting the table toTempDB.
[!WARNING] Exam Trap 2: Hardcoding Integer Values on Extensible Base Enums Questions frequently ask which code snippet is correct when checking an extensible enum. Options containing
if (myTable.Status == 2)are traps. The compiler assigns hash-based integer IDs to extensible enum values. The only correct approach is referencing the symbolic enum literal:if (myTable.Status == MyEnum::Approved).
[!WARNING] Exam Trap 3: Confusing Field Fixed with Related Field Fixed Relations Exam candidates frequently invert these two relation types. Remember the rule: Field Fixed filters the current (source) table buffer, whereas Related Field Fixed filters the foreign (target) table buffer. In polymorphic document references like
DocuRef, matchingDocuRef.RefTableId == tableNum(CustTable)is a Related Field Fixed relation from the perspective of tables pointing to DocuRef.
[!WARNING] Exam Trap 4: Believing Base Table Indexes Can Be Modified in an Extension When an existing index on a standard table causes performance bottlenecks, an exam question may propose modifying the standard index via an extension (e.g., adding an included column or changing
AllowDuplicates). This is impossible because standard indexes are immutable. The valid solution is creating a new non-clustered index in the table extension.
A developer is designing a batch processing framework that aggregates 500,000 transaction records, performs temporary calculations, and joins the temporary data directly with the SalesTable and SalesLine regular tables in SQL Server. Which table type should the developer select and why?
A developer needs to evaluate the status of an order record in X++ where the underlying Base Enum has its IsExtensible property set to True. How must the developer write the condition to conform to Microsoft best practices and avoid runtime errors?
In Dynamics 365 Finance and Operations table architecture, which relation type is used when a relationship between two tables must be filtered based on a constant discriminator value in the related (target) table?
A developer creates a table extension for the standard CustTable. Which modification is permitted by the Application Object Server (AOS) extension framework?