The X++ delta — what changed in the language, runtime and data-access model
The source and target language are both X++, so this chapter is the delta — Chain of Command semantics, attribute-driven extensions, the removal of client-side X++, RunBase versus SysOperation, ttsbegin/ttscommit nesting, temporary table flavours, RecId and DataAreaId invariants, and the performance patterns that changed because the database moved to a cloud-hosted SQL service.
What you will be able to do
Identify every language and runtime change between AX 2012 X++ and current D365 X++ that affects migrated code
Explain Chain of Command method semantics, including the next call, final modifier and attribute registration
Describe why client-side X++ no longer exists and what that means for code that assumed a rich client
Choose correctly between RunBase and SysOperation for new and migrated batch jobs
Apply the correct transaction-scope pattern using ttsbegin/ttscommit reference counting
Select the right temporary-table flavour for a given use case and avoid the performance traps of each
Introduction
This chapter is unusual in the context of this site. Every other source system has a different language — ABAP, C, PL/SQL, L4G, SuiteScript. AX 2012 and D365 both use X++. The developer's task is not to learn a new language but to learn what changed in the one they already know.
Chain of Command: the mechanics
A Chain of Command extension is a class decorated with [ExtensionOf(classStr(TargetClass))] (or the equivalent for tables, forms and data entities). The class must be marked final — it cannot itself be extended by another class.
The removal of client-side X++
Server tier (the AOS) — batch jobs, posting logic, data access Client tier (the rich client process) — form interaction, WinAPI calls, COM automation, local file access
X++ transactions are reference-counted. Each ttsbegin increments a nesting counter; each ttscommit decrements it. Only when the counter reaches zero does the actual SQL COMMIT execute. A ttsabort at any nesting depth discards the entire transaction and throws an exception.
Temporary tables: InMemory versus TempDB
Heap-allocated in the AOS process memory Scoped to the variable that declares the buffer Cannot be joined in SQL (the database does not know they exist) Cannot back a form data source in the D365 web client Best for: small lookup sets, intermediate computation within a single method, containers of parameters
Performance patterns, RecId and DataAreaId
RecId is a 64-bit integer, unique per table, assigned by the system at insert time. It is the surrogate primary key and the FK wire in most relationships. AX 2012 and D365 share this invariant. The delta for migrated code:
Before-and-after code examples
```xpp // In the CUS layer, the entire method body is replaced: boolean validateWrite() { boolean ret; ret = super(); // calls SYS layer version
Knowledge check
Summary
The language is still X++. The select family, the type system, the class hierarchy, the table model, the transaction primitives — all of these are recognisable. What changed is not the vocabulary but the contract: you extend rather than replace, you run server-side rather than client-side, you respect cloud-SQL performance constraints…