“Today we are going to analyze a real runnable X++ class and understand an important concept used in almost every Dynamics 365 Finance & Operations project — Query ranges and how values are passed to them.”
“This is not theory. This is exactly how Microsoft writes code in real projects.”
internal final class Ansari_Test_QueryValueVsValue
This class is created to:
Compare two ways of passing values to a query range
Test:
.value(_custAccount)
.value(queryValue(_custAccount))
Prove that both work, but best practices differ
public static void main(Args _args)
This is the entry point of the class
The system calls this method when:
A menu item is executed
Or the class is run directly
This allows us to:
Execute queries
Print results using info()
Query query;
QueryBuildDataSource qbds;
QueryRun queryRun;
SalesTable salesTable;
| Object | Purpose |
|---|---|
Query |
Holds the query definition |
QueryBuildDataSource |
Defines tables and ranges |
QueryRun |
Executes the query |
SalesTable |
Holds fetched records |
“This is the standard structure for executing queries in X++.”
CustAccount declared like this?CustAccount custAccount = "US-004";
CustAccount is an EDT (Extended Data Type)
It is:
A string
Controlled
Clean
This makes it a trusted input
“This is why Microsoft sometimes passes it directly without
queryValue().”
info("===== Using .value(_custAccount) =====");
Marks Test Case 1
Helps us clearly identify:
Which query logic is running
Which output belongs to which approach
qbds.addRange(fieldNum(SalesTable, CustAccount))
.value(custAccount);
A range is added on SalesTable.CustAccount
The value is passed directly
Works because:
The value is a trusted string
Comes from an EDT
“This is why you often see this pattern in OOB classes.”
queryRun = new QueryRun(query);
while (queryRun.next())
{
salesTable = queryRun.get(tableNum(SalesTable));
}
QueryRun executes the query
next() fetches one record at a time
get() retrieves the table buffer
info(strFmt("SalesId: %1 | CustAccount: %2",
salesTable.SalesId,
salesTable.CustAccount));
Records are fetched correctly
Confirms:
.value(_custAccount) works
info("===== Using .value(queryValue(_custAccount)) =====");
This marks Test Case 2
Demonstrates best practice
queryValue() actually do?.value(queryValue(custAccount));
queryValue():
Converts the value into a query-safe string
Adds:
Proper quoting
Formatting
Escaping
Works for:
Strings
Enums
Integers
Dates
“This makes the query safer and future-proof.”
Because:
The value is a clean string
No special characters
Both formats are accepted by the query engine
“Working code does not always mean best practice code.”
.value(_custAccount) acceptable?When the value:
Comes from an EDT
Is controlled
Is not user-manipulated
Common in:
OOB classes
Dialog-based filters
queryValue() be used?Always use queryValue() when:
The field is:
Enum
Int
Date
The value comes from:
User input
Integration
External systems
“Both approaches work. Microsoft uses
.value(value)for trusted string EDTs.
But as developers, we should preferqueryValue()in custom code because it is safer, cleaner, and future-proof.”
.value(value)is acceptable for trusted string inputs and used in OOB code, whilequeryValue()is the recommended and safer approach for custom and dynamic scenarios.
“Always ask yourself one question before choosing:
Is this value fully trusted?
If not — usequeryValue().”
First read the answer fully, then try to explain it in your own words. After that, open a few related questions and compare the concepts. This method helps you remember the topic for a longer time and improves exam preparation.