Domain 4 β€” Module 1 of 6 17%
11 of 28 overall
Domain 4: Develop and Test Code Free ⏱ ~16 min read

X++ Fundamentals: Syntax & CRUD

Learn X++ structured programming, CRUD data operations, global functions, and best practice rules.

X++ Fundamentals: Syntax & CRUD

Welcome to Domain 4 β€” the heart of MB-500. X++ powers every customisation in D365 Finance and Operations.

Simple explanation

Think of X++ as C# with a built-in database.

X++ has SQL-like statements baked into the language β€” select, while select, insert. It also has built-in transactions (ttsBegin/ttsCommit). If you know C# or Java, X++ feels familiar with a few unique twists like the container type and 1-based indexing.

Variables and Data Types

TypeDescriptionExample
int / int64Integerint count = 10;
realDecimalreal price = 29.99;
strStringstr name = "Contoso";
booleanTrue/falseboolean active = true;
date / utcdatetimeDate valuesdate today = systemDateGet();
containerMixed-type collectioncontainer c = [1, "hello", true];

πŸŽ“ Sophie’s first day: β€œCarl said the biggest surprise is the container type β€” like a tuple holding any mix. Indexing starts at 1, not 0!”

Containers

container data = [1001, "Contoso", 29.99];
int id   = conPeek(data, 1);    // 1001 (1-based!)
str name = conPeek(data, 2);    // "Contoso"
int size = conLen(data);         // 3
container updated = conIns(data, 2, "NYC"); // new container
Exam tip: Container indexing starts at 1

conPeek(c, 0) causes a runtime error. Containers are 1-based. The exam tests this.

Control Flow

if (custTable.AccountNum == "1001")
    info("Found");
else
    error("Not found");

switch (salesLine.SalesStatus)
{
    case SalesStatus::Backorder: info("Back"); break;
    case SalesStatus::Delivered: info("Done"); break;
}

for (int i = 1; i <= 10; i++)
    info(strFmt("Item %1", i));

πŸ—οΈ Vik: β€œ90% of the time you loop with while select, not plain for/while.”

Reading Data β€” select

CustTable custTable;
select firstOnly custTable where custTable.AccountNum == "1001";
if (custTable)
    info(strFmt("Customer: %1", custTable.Name));

while select

CustTable custTable;
while select custTable where custTable.Blocked == CustVendorBlocked::No
{
    info(strFmt("%1 - %2", custTable.AccountNum, custTable.Name));
}

Joins and aggregates

CustTable custTable;
CustTrans custTrans;
while select custTable
    join custTrans where custTrans.AccountNum == custTable.AccountNum
{
    info(strFmt("%1: %2", custTable.Name, custTrans.Voucher));
}

select count(RecId) from custTable where custTable.Blocked == CustVendorBlocked::No;
select Keywords
KeywordPurpose
firstOnlyReturn one record
order bySort results
group by / count / sumAggregates
join / outer joinTable joins
exists join / notexists joinExistence filter
forUpdateLock for modification

Writing Data β€” Insert, Update, Delete

// INSERT
CustTable custTable;
ttsBegin;
    custTable.AccountNum = "9001";
    custTable.Name = "New Customer";
    custTable.insert();
ttsCommit;

// UPDATE (forUpdate required!)
ttsBegin;
    select forUpdate custTable where custTable.AccountNum == "9001";
    if (custTable) { custTable.Name = "Updated"; custTable.update(); }
ttsCommit;

// DELETE
ttsBegin;
    select forUpdate custTable where custTable.AccountNum == "9001";
    if (custTable) { custTable.delete(); }
ttsCommit;

Key patterns: ttsBegin/ttsCommit for transactions. forUpdate locks the record. Always check if (buffer) before update/delete.

Exam tip: tts nesting

Transaction scopes nest. Only the outermost ttsCommit commits. Any exception rolls back everything.

Global Functions

FunctionPurpose
strFmt("Hello %1", name)String formatting
conPeek(c, 1) / conLen(c)Container ops
systemDateGet()Current date
info() / warning() / error()Infolog messages
classStr() / tableStr()Compile-time names

Best Practice Rules

The compiler includes a BP checker β€” like ESLint for X++.

RuleCatchesFix
Missing labelHardcoded UI stringsUse @SYS labels
Select without whereUnbounded queriesAdd where clause
Unused variableDeclared not usedRemove it

πŸ‘¨β€πŸ’» Elena: β€œUse strFmt for all formatting, not concatenation. Cleaner, faster, translatable.”

Question

select firstOnly vs while select?

Click or press Enter to reveal answer

Question

What does ttsBegin/ttsCommit do?

Click or press Enter to reveal answer

Question

What keyword before update()/delete()?

Click or press Enter to reveal answer

Knowledge Check

Correct X++ to fetch one customer?

Knowledge Check

Vik updates without forUpdate. What happens?

Knowledge Check

conPeek(data, 0) on a container?


Next up: Object-Oriented X++ β€” classes, inheritance, QueryBuilder, and attributes.