Skip to main content

Code Examples

Practical X++ code patterns for working with views — computed columns, layered view composition, and basic data access.


Selecting from a View​

A view buffer behaves like a read-only table — use standard X++ select syntax:

SAMOCustSummaryView samoView;

// Simple select
select samoView
where samoView.CustGroup == '10';

info(strFmt("Customer: %1", samoView.CustName));

// While-select loop
while select samoView
where samoView.TransDate >= today() - 30
{
info(strFmt("%1 — %2", samoView.AccountNum, samoView.Amount));
}

// Joining a view with a table
SalesTable salesTable;
SAMOCustSummaryView samoView;

select samoView
join salesTable
where salesTable.CustAccount == samoView.AccountNum;
danger

Do not call insert(), update(), or delete() on a view buffer. Views are read-only. The compiler will not prevent the call (inherited from Common), but the runtime will throw an error.


Computed Columns Using SysComputedColumn​

Computed fields are defined by a static method that returns a SQL expression string. The method runs at sync time (not at query time) and the returned string is spliced into the CREATE VIEW SQL.

/// <summary>
/// Returns the full name by concatenating first and last name.
/// </summary>
private static server str samoFullName()
{
DictView dictView = new DictView(tableNum(SAMOCustSummaryView));
str dsName = identifierStr(CustTable);
str firstName = dictView.computedColumnString(
dsName,
fieldStr(DirPartyTable, FirstName),
FieldNameGenerationMode::FieldList);
str lastName = dictView.computedColumnString(
dsName,
fieldStr(DirPartyTable, LastName),
FieldNameGenerationMode::FieldList);

return SysComputedColumn::concat(firstName, ' ', lastName);
}

This produces SQL like:

CREATE VIEW [dbo].[SAMOCUSTSUMMARYVIEW] AS
SELECT
...
CONCAT(T1.FIRSTNAME, ' ', T1.LASTNAME) AS SAMOFULLNAME,
...
FROM CUSTTABLE T1

Replacing Display Methods with Layered Views​

Display methods execute per-row in X++ and cannot be sorted or filtered. Layered views replace them with a real SQL column.

The Problem: Display Method​

// Runs per row — not sortable, not filterable
display Amount openInvoiceTotal(CustTable _custTable)
{
return (select sum(AmountMST) from custTransOpen
where custTransOpen.AccountNum == _custTable.AccountNum
).AmountMST;
}

The Solution: Layered Views​

  1. View 1 — SAMOCustOpenTotalView: aggregates CustTransOpen by AccountNum, returns one row per customer with Sum(AmountMST).
  2. View 2 — SAMOCustWithTotalView: outer-joins CustTable to SAMOCustOpenTotalView, exposing all customer fields plus the aggregated total.

The form data source becomes SAMOCustWithTotalView — the total column is a real SQL column that users can sort, filter, and export.


SysComputedColumn Helper Methods​

MethodSQL EquivalentPurpose
ifCASE WHEN ... THEN ... ELSE ... ENDConditional logic.
concatCONCAT(...)String concatenation.
castCAST(... AS ...)Type casting.
isNullValueISNULL(...)Null replacement.
equalExpression=Equality comparison for CASE expressions.
notEqualExpression<>Inequality comparison.
andANDLogical AND for combining conditions.
orORLogical OR for combining conditions.
sum, count, min, max, avgAggregate functionsAggregation expressions.
warning

Always use SysComputedColumn helpers and DictView.computedColumnString() to generate column references — never hard-code physical SQL column names, as these can differ from the AOT field names.