You are on page 1of 82

My Collection

This document is provided "as-is". Information and views expressed in this document, including URL and other Internet Web site references,
may change without notice. This document does not provide you with any legal rights to any intellectual property in any Microsoft product or
product name. You may copy and use this document for your internal, reference purposes. You may modify this document for your internal,
reference purposes.

Table of Contents
Chapter 1
Classes and Methods
Queries in the AOT for Data Access

true

Classes and Methods [AX 2012]


Updated: March 11, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
This section contains topics about types in the X++ language.
Classes in X++
Methods in X++
Interfaces Overview
Microsoft Dynamics AX Class Overview

See also

Microsoft Dynamics AX Design Patterns


X++ Language Programming Guide

true

Classes in X++ [AX 2012]


Updated: September 28, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
A class is a software construct that defines the data and methods of the specific concrete objects that are subsequently constructed from that
class. The data represents the state of the object. The methods represent the behavior of the object.
Variables are the data for the class. Variables in an X++ class are specific to objects that are constructed from that class. Every object constructed
from the class declaration has its own copy of the variables. Such variables are known as instance variables. You cannot declare static variables
in X++.
Methods are the sequences of statements that operate on the data. Methods are typically declared to operate on the instance variables of the class,
and are known as instance methods or object methods. In X++ you can also declare static methods.

In This Section

Declaration of Classes
Constructors
Destructors
Creating a Subclass
Tables as Classes

See also

Methods in X++

Declaration of Classes [AX 2012]


Updated: June 20, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
You create application classes by using the Application Object Tree (AOT).

Creating a Class in the Application Object Tree

You create an application class by following these steps:


1.

In the AOT, locate the Classes node.

2.

Right-click the Classes node and click New Class in the shortcut menu.

3.

Expand the Class1 node, so you can see the classDeclaration node.

4.

Right-click the classDeclaration node, and then click View Code. This displays the code Editor window.

In the classDeclaration code block, before the open brace {, the class declaration is decorated with the public modifier. All classes in Microsoft
Dynamics AX are public. If you remove the public modifier, the system still treats the class as public.
Other modifiers can be specified on the class declaration, including final and extends.

Creating Variables in a Class

All classes are public, but all member variables are implicitly private. Even though all member variables are private, you cannot decorate a
member variable with the private keyword. All member variables belong only to object instances of the class. You cannot decorate a member
variable with the static keyword. The following steps exemplify these rules:
1.

Right-click the classDeclaration node, and then click View Code.

2.

In the code Editor window for the classDeclaration, add the following declaration of a string variable on a line between the open and
close braces {}:
str firstName;

The X++ code for the classDeclaration now looks like the following.
public class Class1
{
str firstName;
}

You can provide access to a member variable by returning it from a simple instance public methods that get and set its value.
For information about how to write variable declarations, see Declaration of Variables.

Creating Accessor Methods in a Class

In this section you add simple public methods that get and set the value of the member variable firstName.

Add a Getter Accessor Method


Follow these steps to add a method that gets or returns the value of a member variable:
1.

Right-click the Class1 node, and then click New > Method.

2.

Rename the method1 node to getFirstName.

3.

In the code Editor window, paste in the following X++ code for the method.
public str getFirstName()
{
return firstName;
}
Note

The this keyword cannot be used to reference member variables such as firstName.

Add a Setter Accessor Method


Follow these steps to add a method that sets the value of a member variable:
1.

Right-click the Class1 node, and then click New > Method.

2.

Rename the method1 node to setFirstName.

3.

In the code Editor window, paste in the following X++ code for the method.
public void setFirstName(str _firstName)
{
firstName = _firstName;
}

Test the Accessor Methods


The following X++ job tests the preceding getter and setter accessor methods.
static void AccessorJob61(Args _args)
{
Class1 c1;
c1 = new Class1(); // new method is inherited from the Object class.
c1.setFirstName("Isaac");
print c1.getFirstName();
pause;
/*** Content of the Print window:
Isaac
***/
}

See also

Best Practices for Class Declarations


Creating a Subclass

Constructors [AX 2012]


Updated: November 30, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
To create an instance of a class (an object), you have to instantiate it. The default constructor is the new method:
// Declares a variable to refer to a Point object
Point myPoint;
;
// Allocates an instance of a Point object
myPoint = new Point();
It is a best practice to make the new method protected, and instead, use a static construct method, or static new method as the public constructor
for the class. If no initialization is required, use a static construct method, otherwise use a static new method. For more information, see Best
Practices for Constructors.

Creating Other Objects from a Constructor

A class constructor can instantiate other objects, in addition to creating an instance of the class. The following code illustrates one such situation
by declaring a Rectangle class that uses two Point objects to define its bounds.
class Rectangle
{
Point lowerLeft;
Point upperRight;
}

new(real _topLeftX, real _topLeftY, real _bottomRightX, real _bottomRightY)


{
lowerLeft = new Point(_topLeftX, _topLeftY);
upperRight = new Point(_bottomRightX, _bottomRightY);
}

Accessing Members in a Object

X++ does not allow you to access the variables of an object by referring to the names of the variables, qualified with the name of the object:
myPoint.x = 10.0; //Not possible
myPoint.y = 25.7; //Not possible
The only way to access the member variables in a class is through accessor methods. For information about accessor methods, see Accessor
Methods.

See also

Destructors

Destructors [AX 2012]


Updated: October 11, 2008
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
A destructor is used to explicitly destroy a class object.
X++ objects are destructed automatically when there are no more references to them. You can destruct them explicitly in the following ways:

Use the finalize method.

Set the object handle to null.

finalize

Use the finalize method to explicitly destruct an object. There are no implicit calls to the finalize method. You must call it to execute the
statements in it.
// From any method in a class.
{
...
if(Condition)
// Removes object from memory.
this.finalize();
...
}
The finalize method is also where to put any other clean-up code. For example, if your class uses a DLL module, you can use the finalize method
to release the DLL when you no longer need it.
Caution

Use finalize carefully. It will destruct an object even if there are references to it.

Set an Object Handle to null

Set the object handle to null to terminate an object. This only destroys the object if there are no other object handles pointing to it. Check that
other programmers haven't already used the object handle.
For example:
// Create an object handle of the type MyObject.
MyObject mo;
;
// Create an object of MyObject type and
// link it to the object handle.
mo = new myObject();
// Terminate the object.
mo = null;

See also

Constructors
Declaration of Classes
Declaration of Methods

true

Creating a Subclass [AX 2012]


Updated: November 15, 2013
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
Subclasses are classes that extend (inherit from) other classes. In X++, a new class can only extend one other class; multiple inheritance is not
supported. If you extend a class, it inherits all the methods and variables in the parent class (the superclass).
Subclasses enable you to reuse existing code for a more specific purpose, saving time on design, development, and testing. To customize the
behavior of the superclass, override the methods in your subclass.
For terminology, a superclass is often called a base class, and a subclass is often called a derived class.
For more information about overriding a method, see Overriding a Method.

Example

The following example creates a class called Point and extends it to create a new class called ThreePoint.
class Point
{
// Instance fields.
real x;
real y;
;

// Constructor to initialize fields x and y.


new(real _x, real _y)
{
x = _x;
y = _y;
}

class ThreePoint extends Point


{
// Additional instance fields z. Fields x and y are inherited.
real z;
;
// Constructor is overridden to initialize z.
new(real _x, real _y, real _z)
{
// Initialize the fields.
super(_x, _y);
z = _z;
}
}

Preventing Class Extension

You can prevent classes from being extended by using the final modifier:
public final class Attribute
{
int objectField;
}

See also

Table Inheritance Overview


Classes in X++

Tables as Classes [AX 2012]


Updated: September 30, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
Application tables can be viewed as being similar to application classes in Microsoft Dynamics AX, but with the following differences from
classes:

Tables are persistent.

Table fields are always public.

A table in the AOT almost always corresponds to a real object.

The definition of a table must sometimes be erased if you later want another table to extend it.

See also

Table Inheritance Overview


Classes in X++
true

Methods in X++ [AX 2012]

Updated: March 7, 2012


Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
The following blocks of code are standard for X++ application classes:
Code block type

Description

classDescription declaration

Contains class modifiers such as public, private, and extends.

block

Also contains the field members for objects that are constructed from this class. IntelliSense can display a list of the members when you type the
X++ keyword this.

new method

The constructor. This method can be called only by using the new keyword. The syntax is typically similar to:
myClassInstance = new MyClass();
Derived classes can call the new method of their constructor by calling super method reference.

finalize method

The destructor method.


However, in X++ this is a destructor only by convention. The finalize method is not called automatically by the system during garbage
collection.

Additional methods for a class fall into the following types:

Instance methods

Static methods

Main methods

Note

Methods can be created on many kinds of items in the AOT other than just classes. The list includes the following:

Maps

Views

Data Sets

Forms

Queries

Instance Methods

Instance methods, or object methods, are embedded in each object that is created from the class. They are called by using the following syntax:
objectHandleName.methodName();
You must instantiate the object before you can use the method.
Caution

If you later convert an instance method to a static method, you must restart the Microsoft Dynamics AX client for the compiler to note the change. Once you have converted the
instance method to a static method, you can no longer call this method from the instance of the class -- only the class itself. Static methods are discussed in the next section.

Static Methods

Static methods, or class methods, belong to a class and are created by using the keyword static. They are called by using the following syntax:

ClassName::methodName();
You do not need to instantiate an object before you use static methods. Static methods are widely used in Microsoft Dynamics AX to work with
data that is stored in tables.
Note

It is not possible to use member variables in a static method.

For more information, see Static Methods.

Main Methods

A main method is a class method that is executed directly from a menu option.
static void main (Args _args)
{
// Your X++ code here.
}
The method should only create an instance of the object and then call the necessary member methods. The _args parameter allows you to transfer
data to the method.
For more information, see Activating a class from a menu item.

See also

Declaration of Methods
Method Modifiers
Overriding a Method
Best Practices for Methods
Table Methods

Declaration of Methods [AX 2012]


Updated: October 5, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
Methods are created using the Application Object Tree (AOT). When methods are created, MorphX creates a default declaration that must be
altered.
Method declarations consist of a header and a body. The method header declares the name and return type (possibly void) of the method, the
method modifiers, and parameters. The method body consists of variable declarations, method declarations, and statements.

Return Type

If a method does not return anything, you must specify this with the void keyword.
void methodName()
{
...
}
If a method returns something, you must specify the return type and include a return statement.
int methodName()
{
return myInt;
}

Syntax

Method declaration

Heading Body

Heading

[ Modifiers ] ReturnType MethodName ( ParameterList )

Modifiers

[client] [server] [edit | display | public | protected | private] [static | abstract | final ]

ReturnType

Datatype | void | anytype

MethodName

Identifier

ParameterList

[ Parameter { , Parameter }]

Parameter

Datatype Variableidentifier [ = Expression ]

Body

{ [ VariableDeclarations ] [ EmbeddedFunctionDeclarations ] [ Statements ] }

EmbeddedFunctionDeclaration

Heading {[ VariableDeclarations ] [ Statements ]}

Note

If you use the anytype return type, the method can return any data type.

Examples

Method Without a Return Type


void update ()
{
// Variable declared and initialized
CustTable this_Orig = this.orig();

// First statement in body (begin transaction)


ttsBegin;
this.setNameAlias();
// Calls super's implementation of update
super();
this.setAccountOnVend(this_Orig);
if (this_Orig.custGroup != this.custGroup)
ForecastSales::setCustGroupId(
this.accountNum,
this_Orig.custGroup,
this.custGroup);

// Commits transaction
ttsCommit;
}

Method with Parameters


boolean checkAccountBlocked(AmountCur amountCur)
{
if (this.blocked == CustVendorBlocked::All
||(this.blocked == CustVendorBlocked::Invoice
&& amountCur > 0 ))
return checkFailed(strFmt("@SYS7987",this.accountNum));

return true;
}

checkAccountBlocked returns a Boolean value and acts on the parameter amountCur.

Methods with Modifiers


Only the method headers are shown in the following examples.
// A method that cannot be overridden
final int dontAlterMe()
// A static method
static void noChange()

// A display method that returns an integer


display int value()

See also

Method Modifiers
Using Optional Parameters
true

Method Modifiers [AX 2012]


Updated: October 6, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
There are several modifiers that can be applied to method declarations. Some of the modifiers can be combined (for example, final static).
The following table describes the method modifier keywords of the X++ language.
Modifier

Description

abstract

The method is declared but not implemented in a parent class. The method must be overridden in subclasses.
If you try to create an object from a subclass where one or more of the abstract methods belonging to the parent class have not been overridden, you will get a compiler
error.
Note
Classes can also be abstract. Sometimes a class represents an abstract concept, but it should not be instantiated: Only subclasses should be instantiated. Such base
classes can be declared abstract. Consider the case where the programmer wants to model the concept of an account. Accounts are abstractonly derived classes
(ledger accounts and so on) exist in the real world. This would be a clear case for declaring the Account class abstract.

client

Establishes the location where the method is to be executed (on the client).
Can only be used on static methods. If the method is not static, specify the location by using the class property RunOn.

display

Indicates that the method's return value is to be displayed on a form or a report. The value cannot be altered in the form or report.

The return value is typically a calculated value, for example, a sum.


For more information about the display and edit modifiers, see Using the display Method Modifier.

edit

Indicates that the method's return type is to be used to provide information for a field that is used in a form. The value in the field can be edited.

final

Indicates that the method cannot be overridden in any class that derives from its class.

public

Methods that are declared as public are accessible anywhere the class is accessible and can be overridden by subclasses. Methods that have no access modifier are
implicitly public.

protected

Methods that are declared as protected can only be called from methods in the class and in subclasses that extend the class where the method is declared.

private

Methods that are declared as private can be called only from methods in the class where the private method is declared.

server

Establishes the location where the method is to be executed (on the server).
Can only be used on static methods. If the method is not static, you need to specify the location using the class property RunOn.

static

Specifies that the method is a class method and does not operate on an object.
static methods cannot refer to instance variables and are invoked by using the class name rather than on an instance of the class (MyClass::aStaticProcedure()).
For more information, see Static Methods.

Static Methods [AX 2012]


Updated: October 25, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
In X++ you can decorate a method with the static keyword. This keyword instructs the system to create only one instance of the method
regardless of how many instances of its class you create. This single instance is used throughout your Microsoft Dynamics AX session.
Static methods are generally intended for cases where the following criteria are met:

The method has no reason to access the member variables that are declared in the classDeclaration block of the class.

The method has no reason to call any instance (non-static) methods of the class.

Syntax

Declaring a Static Method


Consider the example of a software key type that is used for piracy prevention. Each instance of a software key can have its own unique value.
But all software keys must conform to the rules of software key design. Therefore the logic to test for software key conformance is the same for
all software keys. The method that contains the conformance validation logic should be static. Here is an example of a method that is declared
with the static keyword:

static public boolean validateSoftwareKey(str _softwareKeyString)


{
// X++ code here.
}

Calling a Static Method


In the following example, there is no need to first construct an instance of the SoftwareKey class before you call a static method on the class. To
call the static method validateSoftwareKey, the syntax starts with the name of the class that contains the method. A pair of colon (::) characters is
used to connect the class name to the static method name.
boolean yourBool = SoftwareKey::validateSoftwareKey(yourSoftwareKeyString);

See also

Declaration of Methods
Method Modifiers
Best Practices for Method Modifiers
Methods in X++

Method Access Control [AX 2012]


Updated: July 20, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012

In X++, you use the accessor keywords public, protected, and private to control whether the methods in other classes can call the methods on
your class. The accessor keywords on methods also interact with the rules for class inheritance. The following table describes the accessor
keywords you use with methods.
public

Methods that are declared as public can be called from anywhere the class is accessible. In addition, a public method can be overridden by a subclass, unless the
method is declared as final.

protected

Methods that are declared as protected can be called only from the following:

From methods in the class.

From methods in a subclass of the class that contains the protected method.
Methods that are protected can be overridden in subclasses.

private

Methods that are declared as private can be called only from methods in the class where the private method is declared. No private method can be overridden in a
subclass.
When you create a new method, the default accessor keyword that appears in the code editor is private. This is the most conservative default for maximum security.

Note

In the Application Object Tree (AOT), all classes under AOT > Classes are public. Explicit use of the public keyword is recommended in the classDeclaration code block for each
class, but the class is public even if the public keyword is omitted.

Static and Instance Methods

The accessor keywords on methods never restrict call between two methods that are in the same class. This is true regardless of which of the two
methods are static or non-static.
In a static method, calls to the new constructor method are valid even if the new constructor method is decorated with the private modifier. The
syntax for these calls requires the use of the new keyword of X++. The code in a static method must construct an instance object of its own class
before the code can call any instance methods on the class.

Increase Access When Overriding

When a method is overridden in a subclass, the overriding method must be at least as accessible as the overridden method. For example, the
following X++ compiler rules apply to overriding a protected method in a subclass:

A public method in a superclass can be overridden only by a public method in the subclass.

In a subclass, a public method or a protected method can override a protected method of the superclass.

In a subclass, a private method cannot override a protected method of the superclass.

Design Pattern of private new

All application classes are under AOT > Classes. Every application class has the constructor method named new, even if the class has no new
node in the AOT. If the class has no explicit new node, the implicit new method is public.
A design pattern that is sometimes used in Microsoft Dynamics AX is to declare the explicit new constructor method as private. Then a public
static method is added to call the new method. The static method can restrict or control the call the new method based on various conditions, if
necessary.

See also

Method Modifiers
Declaration of Methods

Using Optional Parameters [AX 2012]


Updated: June 20, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
It is possible to initialize parameters in the method declaration. This makes the parameter an optional parameter. If no value is supplied in the
method call, the default value is used.

Code Example 1: Function used as the Default

The following methods are considered to be members of the MyClass1 class, which includes the field member birthDate.
public class MyClass1 // classDeclaration
{
date birthDate;
}

Next, the class contains a constructor that takes a date type as a parameter. That value is assigned to the field member birthDate.
void new(date _date)
{
birthDate = _date;
}

Next is the CalculateAgeAsOfDate method, for which the following are true:

The method references the birthDate field.

The method has an optional parameter. In this example, the default value is the return value of a function.

The method is called by the Main method.

public real CalculateAgeAsOfDate // X++


( date _calcToDate = today() ) // Parameter is optional for callers.
{
return (_calcToDate - birthDate) / 365;
}

Next is the Main method which calls the CalculateAgeAsOfDate method twice.
static public void Main(Args _args)
{
MyClass1 mc = new MyClass1(13\5\2010); // birthDate is initialized.
// Optional parameter's default is used.
print "Age in years: " + num2str(mc.CalculateAgeAsOfDate(),2,0,0,0);
// January 2, 2044 is the parameter value for _date.
print "Age in years: " + num2str(mc.CalculateAgeAsOfDate(2\1\2044),2,0,0,0);
pause;
}

Code Example 2: Invalid Sequence of Parameters

All required parameters must be listed before the first optional parameter. In the following invalid example, the required parameter _i3 is listed
after the optional parameter _i2.
static public int AddThreeIntsA // Invalid X++, does not compile.

(int _i1,
int _i2 = 3,
int _i3) // Required parameter cannot follow an optional parameter.
{
return _i1 + _i2 + _i3;
}

Code Example 3: Cannot Skip to Second Optional Parameter

When calling a method, the caller cannot override the default value of the final optional parameter unless the caller also overrides the default
values of every other optional parameter.
In the following example, the first method has two optional parameters. The second method is a caller of the first method. The caller wants to
override only the _i3 default value, but the compiler requires that all prior optional parameters also be overridden in the call.
static public int AddThreeIntsB
(int _i1,
int _i2 = 2,
int _i3 = 3)
{
return _i1 + _i2 + _i3;
}

Next, the second method has a commented section showing the failed attempt to accept the default of the first optional parameter _i2 while
trying to override the final optional parameter _i3.
static public void Main(Args _args)
{
// No way to skip the first optional parameter (so it can default)
// while also specifying the value of the second optional parameter.
//
//print MyClass1::AddThreeIntsB(1, , 99); // Would fail to compile in X++.

// Settle for overriding both optional parameters.


//
print MyClass1::AddThreeIntsB(1, 2, 99);
pause;
}

See also

Declaration of Methods

Accessor Methods [AX 2012]


Updated: August 6, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
If an object uses another object to do some work on its behalf, the first object sends a message to the second object. In response, the second
object invokes the selected method.
This programming technique is one of the best ways to create models and simulations of complex real-world systems. The following example
defines a Point class so that it uses accessor methods to access the variables x and y.
class Point
{
// Instance variables
real x;
real y;

//Constructor to initialize to a specific or default value


void new(real _x=10, real _y=10)
{
x = _x;
y = _y;
}

//Accessor method
void setX(real _x)
{
x = _x;
}

//Accessor method
void setY(real _y)
{
y = _y;
}

//Accessor method
real getX()
{
return x;
}

//Accessor method
real getY()

{
return y;
}
}

These method declarations illustrate how the Point class provides access to its variables from the outside world. Other objects can manipulate the
instance variables of Point objects by using the accessor methods:
//Declare a variable to refer to a Point object
Point myPoint;

//Create a Point object


myPoint = new Point();
//Set the x variable using the accessor method
myPoint.setX(10.0);
//Set the y variable by means of the accessor method
myPoint.setY(25.7);

By hiding details of the internal implementation of a class, X++ allows the programmer to change the implementation of the class in the future
without breaking any code that uses that class.
Note

The X++ callstack depth is limited to 100.

See also

Methods in X++

Overriding a Method [AX 2012]


Updated: February 20, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
The methods in a class are inherited by any class that extends it. You can alter the functionality of an inherited method by creating a method in
the subclass with the same name and parameters as in the superclass. This is called overriding the method. For example:
// Superclass: Attribute
public class Attribute
{
int objectVariable;
}
void methodAtt()
{
//Some statements
}
// Subclass: ColorAttribute
public class ColorAttribute extends Attribute

{
int addedObjectVariable;
}
void methodAtt()
{
//Some statements
}
ColorAttribute is a subclass of Attribute and therefore inherits the method methodAttr. However, because ColorAttribute defines a method with
the same name and the same number of arguments, the method in the superclass is overridden.

Preventing Method Overriding

Static methods cannot be overridden because they exist per class. To protect other sensitive methods, or core methods, from being overridden,
use the final modifier. In the example below, methodAtt is declared as final, and so it cannot be overridden in any class that extends Attribute.
public class Attribute
{
int objectVariable;
}
final void methodAtt()
{
//Some statements
}
Note

You should not specify new or finalize methods as final.

For more information about inheritance in X++, see Creating a Subclass.

Overriding vs. Overloading

Overloading is where there is more than one method with the same name, but the methods have different signatures (return type or parameter
lists or both). Overriding is where the superclass's implementation of a method is altered by the subclass's implementation of the method, but the
signatures of both methods are the same.
X++ supports overriding, but it does not support overloading.

Difference between method overriding and overloading


Overriding is the concept of having functions of same name and signature in different classes. one in the super class can be made virtual and
other can override the functionality of virtual one. Overloading is the concept of having functions of same name, but different signature in same
class. They are differentiated by the compiler by their signatures.

Overloading methods
1. They appear in the same class or a subclass
2. They have the same name but, have different parameter lists, and can have different return types.

Overriding methods
It allows a subclass to re-define a method it inherits from it's superclass overriding methods:
1. It appears in subclasses
2. They have the same name as a superclass method
3. They have the same parameter list as a superclass method
4. They have the same return type as as a superclass method

5. They have the access modifier for the overriding method may not be more restrictive than the access modifier of the superclass method

Parameters and Scoping [AX 2012]

Updated: October 11, 2008


Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
The scope rules in X++ state that all methods have their own scope. To use data from one scope in a different scope, you have to transfer the data
from one scope into the other scope by using parameters.
A method can take one or more parameters. Within the scope of the method, these parameters are treated like local variables and are initialized
with the value from the parameter in the method-call. The following table shows an example.
Class declaration

Method methodQ

class Parameter

void methodQ(int aval, real bval)

{
int a;

a = aval;

real b;

b = bval;

Here, a class called Parameter is declared. The class has a method (methodQ), which takes two parameters: an integer and a real. Four variables
are visible within the scope of methodQ: aval, bval, a, and b. The a and b variables are in the scope because they are defined in the class
declaration for the class.
ssume that ParameterObject is an instance of the Parameter class. If methodQ is invoked on ParameterObject,
ParameterObject.methodQ(1,2.0);
aval is set to the value 1 within the method and the variable bval is set to 2.0 (it is a real) within the method. The two variables a and b in the
ParameterObject are set to 1 and 2.0, respectively. You can pass the value of any expression as a parameter.

Parameters Are Passed by Value

All parameters are passed by value. You cannot change the value of the original variableyou can change only the local variable in the method,
which is a copy of the original. The following table shows an example.
Class declaration

Method methodA

Method methodB

class ByValue

void methodA(int i)

void methodB()

i = i + 1;

int i = 3;

print i;

print i;

this.methodA(i);
print i;
}

Here, a class ByValue is declared with two methods: methodA and methodB.
methodB has a local variable named i, which is used as a parameter to a call methodA.
methodA uses a parameter called i and therefore has a local variable called i. This local variable has the value of the variable i in methodB
(because it is used as a parameter in the call).
The result of invoking methodB is that the value of i is printed with its initial value in methodB (3), and then i is passed into methodA as a
parameter and printed again with its new value (4). Finally, i is printed again with the value from methodB (3). This illustrates that the two i
variables are two different variables.

true

Scope of Variables in Methods [AX 2012]


Updated: January 28, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
A scope defines the area in which an item can be accessed. Variables defined in a class are available to the methods within that class. Variables in
methods can be accessed only within the current block, as shown in the following figure.

The class A contains methods b and c and class variables. All methods in the class can see and use all variables in the class.
The method b has some local variables that can only be accessed from within method b.
Method c has some local variables, a function d, and a function e. Functions d and e can be seen only inside method c. As functions d and e are
declared inside method c, they have access to their local variablesthe local variables in c and the variables in the class, respectively.

See also

Parameters and Scoping


Variable Scopes

Local Functions [AX 2012]


Updated: July 20, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
You can declare local functions inside a method or a job in X++. A local function can contain code that would otherwise have to be duplicated in
two or more places within your method.
Tip

The best practice is to add private methods to the class rather than to add local functions inside the method.

Code Example of a Local Function

The following X++ job code example shows valid declarations of two local functions named localFunc55b and localFunc66c. Calls to the local
functions occur after the function declarations in the code example, as is required.
static void G_LocalFuncJob2(Args _args) // X++ job.
{
int nn = 654;
void localFunc55b(int _iNum) // The local function.
{
str sInnerString;
sInnerString = "String_in_localFunc55b";

info(strFmt("localFunc55b: %1 , %2 , %3",
_iNum, sInnerString, nn));
}
void localFunc66c()
{
info("Printing from inside localFunc66c.");
}
; // This semicolon marks the end of local function declarations.
localFunc55b(55);
localFunc66c();
// Next print statement would fail to compile,
// because sInnerString is restricted to the
// scope of the local function in which it is declared.
//print sInnerString; pause;
}
/*** Infolog window display:
Message (07:38:54 pm)
localFunc55b: 55 , String_in_localFunc55b , 654
Printing from inside localFunc66c.
***/

Declaration of Local Functions

The local functions must be declared physically above any non-declaration statements that exist in the method or job.

You can declare more than one local function in your method. But all local functions must be declared in an uninterrupted series, with
the set terminated by one semicolon.

Scoping of Variables

Code that is inside the local function can access variables that are declared in the method or job that contains the local function.

Code that is outside the local function cannot access variables that are declared in the local function.

Calls to Local Functions

A local function can be called only by code in the same method or job where the local function is declared.

An X++ local function should never call itself. Such recursion can prevent the successful compile of X++ to .NET Framework CIL.
Note

X++ local functions are transformed into inline code when the X++ method is compiled into CIL.

See also

Methods in X++
Best Practices for Local Functions

Server/Client Location of Methods [AX 2012]


Updated: February 22, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
The table below describes what the default client/server location is for different kinds of methods, and whether this default behavior can be
changed.

Default behavior

Can be
changed

Class Static Methods

Run in the same location as that designated by the RunOn property for the class.

Yes

Class Instance

Run in the same location as the class object. The location of instances of the class is determined by the RunOn property for the class.

No

Table Static Methods

Run where they are called from (RunOn property is Called from).

Yes

Table Instance

Run where they are called from (RunOn property is Called from).

Yes

Methods

The standard table methods insert, doInsert, update, doUpdate, delete, and doDelete on the Server (where the data source is). This

Methods

cannot be changed.

The this Object [AX 2012]


Updated: December 6, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
In an X++ method, the keyword this is a reference to the instance of the class or table in which the this keyword is used. The this reference is
never required, but it can clarify your code, and it enhances the behavior of IntelliSense in the code editor.
The this reference can be used in the following ways:

Can be used to qualify the names of other instance (non-static) methods in the same class where the this reference is used. For
example:
boolColorChanged = this.colorItOrange();
Note

In X++ all calls to instance methods must be qualified, either with the this reference or with a variable.
In contrast, C# does not always require such qualification.

Can be used to quality the names of methods that are inherited by the this object.

Can be used to qualify the names of fields on the table that contains the method that the this keyword is used in.

The this reference cannot be used in the following ways:

Cannot be used to qualify the names of member variables that are declared in the classDeclaration code.
C# allows such qualification.

Cannot be used in a static method.

Cannot be used to qualify the names of static methods of the class or table.

See also

Methods in X++

Interfaces Overview [AX 2012]


Updated: November 22, 2013
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
In X++ an interface is a specification for a set of public instance methods. To create an interface, you begin by using the AOT to create a class.
You edit the code of its classDeclaration node to replace the keyword class with the keyword interface. Then you add methods to the interface
just as you would for a class, except no code is allowed inside the method bodies.
The purpose of interfaces is to define and enforce similarities between unrelated classes without having to artificially derive one class from the
other.
Implements and extends
You can add the implements keyword on a class declaration, and this requires the class to declare the methods that are specified by the interface.
A class declaration can implement multiple interfaces by listing them after the single occurrence of the implements keyword, with commas
separating the interface names.
An interface can extend another interface by using the extends keyword. An interface cannot extend more than one interface.
Public
All interfaces are public regardless of whether you explicitly write the keyword public in front of the keyword interface in the classDeclaration.
The methods on an interface are also public, and again the explicit inclusion of the keyword public is optional.
All interface methods that a class implements must be declared with the explicit keyword public in the class. Also, a class that implements an
interface must also be declared with public.

Related Code Examples

This section shows the code for an imaginary Automobile class that implements two interfaces. The classDeclaration code for the class is shown,
as is the classDeclaration for one of the interfaces. Also, the code for the getSpeed method is shown for the class and the interface.

IDrivable Interface
First is the classDeclaration for the interface IDrivable.

classDeclaration for interface IDrivable


Next is the specification that the interface IDrivable has for the getSpeed method.

getSpeed method specification on IDrivable

Automobile Class
Now we examine the code in the Automobile class that implements the IDrivable interface.

classDeclaration for Automobile, include the implements keyword


Finally we examine the full implementation of the getSpeed method on the Automobile class. The method contains X++ in its body between the
{}.

getSpeed method implementation

'is' Keyword Works for Interfaces

The following code example demonstrates that the keyword is does work for a class that implements an interface.
static public void Main(Args _args) // X++

{
IDrivable yourIDrivable;
Automobile myAutomobile;
str sTemp = "'is' keyword does Not work for interfaces.";

myAutomobile = new Automobile();

if (myAutomobile is IDrivable)
{
yourIDrivable = myAutomobile;
yourIDrivable.setSpeed(42);
sTemp = int2str(yourIDrivable.getSpeed());
}

Global::info(sTemp);
return;
}
/*** Output to Infolog:
Message (06:46:33 pm)
42
***/

The keyword is also works for a class that extends another class.

Microsoft Dynamics AX Class Overview [AX 2012]


Updated: September 27, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
There are two main kinds of classes in Microsoft Dynamics AX:

Application classes are implemented in X++. They are available in the Classes node in the AOT.

System classes, sometimes called kernel classes, are implemented in C++. They are listed under the System Documentation > Classes
node in the AOT. However, the source code for these classes is not available.

In This Section

Substitute Application Classes for System Classes


Execute Startup Commands
Batch Processing Classes
Image Manipulation Classes
Query Object Model
System Classes Overview

Performing Reflection with the TreeNode Class


Performing File IO with the TextIo Class

See also

System Classes Overview


Classes and Methods

Substitute Application Classes for System Classes


[AX 2012]
Updated: September 29, 2011

Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
You should call the substitute application classes instead of calling the system classes that they extend.
In the Application Object Tree (AOT) under System Documentation > Classes there are several kernel or system classes whose names begin
with a lowercase x. Examples of the x system classes include xApplication and xVersionControl. Some of the x system classes are extended by
X++ application classes which are under AOT > Classes. For example, the Application X++ class extends the xApplication system class.
The X++ classes that derive from the x system classes are called substitute application classes. In the AOT under the Classes node, the icon next
to the substitute application classes differs from the standard icon.

Special X++ Global Variables

Some of the substitute application classes that extend an x system class are associated with a special X++ global variable that represents an
instance of the X++ class. For example, the appl variable references a pre-instantiated object from the Application X++ class. The advantage of
the appl variable is that the system maintains the object throughout the scope of your session. It would be less efficient for your X++ code to
repeatedly use the new Application() syntax to obtain an instance of the Application X++ class.
You should not use the xApplication system class. Use the Application substitute application class instead. You can reference the static members
of the Application X++ class by using the standard syntax Application::checkForNewBatchJobs(). But you should reference the instance
members of the Application class by using its corresponding special system variable appl, if one exists. This pattern applies to most of the x
system classes. The Session substitute application class is one exception to this pattern, because there is no special system variable for Session.
The following table lists x system classes for which there is a corresponding substitute application class. The special X++ global variables are
also shown for those classes that have one.
Application class

System class

Global variable

Runs on

Args

xArgs

(none)

Client and server

Application

xApplication

appl

Server

ClassFactory

xClassFactory

classFactory

Client and server

Company

xCompany

appl.company

Server

Global

xGlobal

(none)

Client and server

Info

xInfo

Infolog

Client

MenuFunction

xMenuFunction

(none)

Client and server

Session

xSession

(none)

Client and server

VersionControl

xVersionControl

versionControl

Client

Example X++ Job that Uses Special Variables

The following X++ job demonstrates the syntax for using several special X++ variables that reference instances of the substitute application
classes.
static void UseSpecialSystemVariablesForXJob(Args _a)
{
TreeNode treeNode2;
Args

args3;

FormRun formRun4;

// appl variable
print appl.buildNo();

// company variable
appl.company().reloadRights(); // referenced through appl

// Infolog variable
treeNode2 = infolog.findNode("\\forms\\custTable");
print treeNode2.AOTgetProperty("Name");

pause; // do want to continue

// classFactory variable
args3 = new Args(formstr(vendTable));
formRun4 = classFactory.formRunClass(args3);
formRun4.init();
formRun4.run();
formRun4.detach();

Global::info("Job is ending. This is a message in the Infolog.");


pause;
}

See also

Microsoft Dynamics AX Class Overview

Execute Startup Commands [AX 2012]


Updated: February 4, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
Use the SysStartupCmd class framework to execute commands at startup.
When Microsoft Dynamics AX starts, calls are made to the *startup methods on the application-substituted kernel classes Application
(Application.startup) and Info (Info.startup).
Caution

The *startup methods are used for vital system and version-specific calls, and you must never directly modify these methods. Instead, use the SysStartupCmd framework. Serious
consequences may follow if the SYS layer versions of the startup methods are not called.

When Microsoft Dynamics AX is started, calls are executed in the sequence shown in the following code.
appl.startup() // The SysStartupCmd class is instantiated here.
sysStartupCmd.applInit()
super()
sysStartupCmd.applRun()
info.startup()
sysStartupCmd.infoInit()
super()
sysStartupCmd.infoRun()

Commands Available when Microsoft Dynamics AX Starts

The commands that are available when Microsoft Dynamics AX starts are listed in the SysStartupCmd.construct method (available in the
Classes node in the Application Object Tree (AOT)). The commands include the following:

AutoRun

AOTImport

Synchronize

Execute a New Command when Microsoft Dynamics AX Starts

1.

Create a class that extends the SysStartupCmd class to perform your specific task.
For example, in the standard application, the SysStartupCmdBuildNoSet class is used to set the build number. Use a similar approach
for your task.

2.

Modify the construct method on the SysStartupCmd class so that your class is called.
Following is an example.
switch (s)
{

// Code lines are left out here.


case 'autorun':
sysStartupCmd = new SysStartupCmdAutoRun(s,parm);
break;
// Code lines are left out here.
}

3.

Add parameters (if necessary) to commands that are executed on startup to the Command to run at application startup field on the
General tab in the Microsoft Dynamics AX Configuration Utility.
Instead of giving the command from the Microsoft Dynamics AX Configuration Utility, you might choose to use the command-line
parameter -startupcmd= MyCommand.

See also

Substitute Application Classes for System Classes

Batch Processing Classes [AX 2012]


Updated: February 14, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
Implement classes by using the batch processing system, and by extending the RunBase and the RunBaseBatch classes.
Remove the Recurrence button from the Batch processing dialog by using the Args::parmEnum method. For more information, see the
procedure later in this topic.
It is recommended that you designate a class to run as a server-bound batch job. Server-bound batch jobs are more secure than jobs that are not
server-bound batch for the following reasons:

The job executes by using the permissions of the user who submitted the job.

The job can interact with the Microsoft Dynamics AX client, which is processing the job, by using only certain Info and Global class
methods. This limits interaction with the client.

Enable a Class to Run as a Server-Bound Batch Job

1.

Create a class that extends the RunBaseBatch class.

2.

Override the RunBaseBatch.runsImpersonated method to return a value of true, as shown in the following example.
public boolean runsImpersonated()
{
return true;
}

3.

Confirm that the class calls only the following Info and Global class methods:
o

add

Info.copy

Info.cut

Info.import

Info.export

Info.line

Info.num

Global::error

Global::info

Global::warning

The Info.line and Info.num methods are inherited from the xInfo class.

Remove the Recurrence Button from the Batch Processing Dialog

When you implement a class by using the batch processing system, call the Args.parmEnum method, and pass the NoYes::Yes system
enumeration value to remove the Recurrence button.
The NoYes system enumeration determines whether the recurrence button is removed from the batch processing dialog. The default value is
NoYes::No.
In the following code example, the InventTransferMultiShip class is implemented. The BatchDialog::main method creates the Batch processing
dialog.
static void noRecurrenceButton(Args _args)
{
Args a;
InventTransferMultiShip inventTransferMultiShip;
;
a = new Args();
inventTransferMultiShip = InventTransferMultiShip::construct();
a.caller(inventTransferMultiShip);
a.parmEnum(NoYes::Yes);
BatchDialog::main(a);
}

Image Manipulation Classes [AX 2012]


Updated: February 14, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
There are two system classes that enable you to manipulate graphics and icons.
The Image Class enables you to load, save, and manipulate individual images. For example, you can capture a screen and save it as an image,
crop or rotate an image, or manipulate the color depth.
The Imagelist Class enables you to work with a set of images that have some common properties, such as size and transparency color. The image
lists that are used in the application can be viewed in the application classes called ImageListAppl_*.

See also

How to: Create an Image List for Controls

Query Object Model [AX 2012]


Updated: February 13, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
The query object model contains classes to define and run a query. These objects are used to define the query data source, the fields returned,
record ranges and relations to child data sources. The following illustration shows the object model.

The query components shown in the previous figure are system classes. The query classes are more visible when you create a dynamic query in
code, but they are also used behind the scenes when you create a static query in the AOT.
System class

Description

QueryRun

Executes the query and fetches the data.

Query

The top level of the query definition. This class holds some properties itself and has one or more related data sources.

QueryBuildDataSource

Defines access to a single data source in the query. If more than one data source exists at the same level in a query, they result in separate SQL statements
that are executed sequentially. If one data source exists as a child of another data source, a join is created between the two data sources.

QueryBuildFieldList

Defines which fields are returned from the database. The default is that the field list is dynamic, which returns all fields from the data source table, map,
or view. Each data source has only one QueryBuildFieldList object, which contains information on all selected fields. It's possible to specify aggregate
functions like SUM, COUNT, and AVG on the field list object.

QueryBuildRange

Defines a subset of records returned based on a single field. A range is translated into a WHERE clause in the query SQL statement. If more than one field
is used to limit the query (WHERE clause), the data source will contain more than one range.

QueryBuildDynalink

Contains information regarding a relation (limitation) to an external record. When the query is run, this information is converted to additional entries in
the WHERE clause of the query SQL statement. Can only exist on the parent data source of a query. The function is used by forms, when two data sources
are synchronized. Then the child data source will contain a dynalink or dynalinks to the parent data source. The function is used even if the two data
sources are placed in two different forms but are still synchronized.

QueryBuildLink

Specifies the relation between the two data sources in the join. Can only exist on a child data source.

See also

How to: Create Queries by Using X++

System Classes Overview [AX 2012]


Updated: January 19, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
System classes (or kernel classes) are implemented in C++. The source for these classes is not available, but documentation is available for some
of the classes in the Reference content.
A system class can have:

Static methods (or class methods)

Dynamic methods

Properties: these are member functions to set properties. For example, LeftMargin.

Note

You cannot override system class methods.

It is not intended that you design your application objects from scratch by using the system classes. Instead, use them to extend or alter the
default functionality in the Application Object Tree (AOT). For example, you could dynamically add extra information to an existing report or
change the available options on a form, depending on the user's choice in a previous form.
Some of the categories of system classes are described as follows.

Collection Classes

The Collection Classes in Microsoft Dynamics AX enable you to create lists, sets, structs, maps, and arrays.

Application Objects Classes

These system classes hold functions that are activated whenever you use the AOT to create your application. For example, the system uses the
FormDesign class when you define the layout of your form in the Designs node in the Application Object Tree. When you click New CheckBox
in the AOT, the system activates the controlName method with a CheckBox type control as parameter.
These classes also enable you to create and modify application objects. For example, if you want to change a property on a form string field, see
Forms System classes and Query System Classes.

Integration Classes

The integration to the environment of Microsoft Dynamics AX is typically implemented by classes. Some examples of classes of this category
are:

COM: call of methods on COM objects

DLL: call of Microsoft Windows DLL functions

IO: Read and write external files

ODBCConnection: an ODBC interface to a foreign database

Classes Extended by Application Classes

A group of system classes whose names begin with "X" are extended by Application classes. For example, the xInfo System class is extended by
the Info Application class. For more information, see Application substituted kernel classes.

true

Performing Reflection with the TreeNode Class [AX 2012]

Updated: November 9, 2009


Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
This topic gives information about performing reflection on Application Object Tree (AOT) items such as tables and classes. In your X++ code
in Microsoft Dynamics AX, you can use the TreeNode class to perform reflection. The TreeNode class can also add nodes to the AOT, such as
adding an element to an enumeration.

X++ Example

Description
The following code example locates the AOT node for a specific base enumeration. All child nodes are checked to determine the next available
integer value for an EnumValue. Then another child node is added under the enumeration. Finally, the code pauses so that you can inspect the
AOT for the new node. When you see the new node, you can click Yes on a dialog box. This resumes the job code, and the job deletes the new
node before it is completed.
The example relies on the following items which are installed with the system.

The #AOT macro. The macro is located in the AOT under the Macros node.

The base enumeration BankAccountType that is in the AOT under \Data Dictionary\Base Enums\.

The example uses the following methods on the TreeNode class:

AOTadd

AOTcompile

AOTdelete

AOTfindChild

AOTfirstChild

AOTgetProperties

AOTgetProperty

AOTnextSibling

AOTsave

AOTsetProperty

AOTToString

findNode

Code
static void Job_TreeNode_AOTsave_Reflection(Args _args)
{
// #AOT is defined in the AOT under Macros.
#AOT
TreeNode tnode2Enum,
tnode3Element
;
int iMaxEnumValue = -1;
str sEnumName = "BankAccountType",
sEnumElementNameNew = "PiggyBankAccount",
sTemp;
;
// Uses the full path to obtain the node for the new enum element
// that this job creates near its completion.
tnode2Enum = TreeNode::findNode(
#BaseEnumsPath
+ "\\" + sEnumName
+ "\\" + sEnumElementNameNew
+ "\\" );
// Deletes the enum element node if it pre-exists.
if (tnode2Enum)
{
info("Deleting the enum element: ["
+ sEnumElementNameNew
+ "], because it pre-exists.");
tnode2Enum.AOTdelete();
}
else
{
info("Not deleting the enum element: ["
+ sEnumElementNameNew
+ "], because it does not pre-exist.");
}
// Finds the node for the target enum, by searching for the name.
tnode2Enum = TreeNode::findNode(#BaseEnumsPath);
tnode2Enum = tnode2Enum.AOTfindChild(sEnumName);
if (tnode2Enum == null)
{
Error("Cannot find treeNode: " + sEnumName);
return;
}
info( "AOToString: " + tnode2Enum.AOTToString() );
// Gets the first child node of the enum.
tnode3Element = tnode2Enum.AOTfirstChild();
info("");
info("Properties of the first child element:");
info(tnode3Element.AOTgetProperties());
info("");
// Inside the while loop the AOTnextSibling method is called.
// This enables the loop to process each child node of the enum.
// An alternative is to use a TreeNodeIterator that is obtained
// from the AOTiterator method.
while (tnode3Element)
{
if ( iMaxEnumValue < any2int(
tnode3Element.AOTgetProperty("EnumValue"))
)
{
iMaxEnumValue = tnode3Element.AOTgetProperty("EnumValue");
}
info( "iMaxEnumValue == " + int2str(iMaxEnumValue) );
tnode3Element = tnode3Element.AOTnextSibling();
}

++iMaxEnumValue;
// The call to AOTadd on the parent returns a new child node of the enum.

tnode3Element = tnode2Enum.AOTadd("PiggyBankAccount");
// Sets the numeric property on the new child.
tnode3Element.AOTsetProperty("EnumValue", iMaxEnumValue);
// Saves the new child into the system by saving the parent enum.
// Then the new child node appears in the AOT.
tnode2Enum.AOTcompile();
tnode2Enum.AOTsave();
// Asks the user to verify that the AOT displays the new node.
sTemp = "Is the new element displayed in the AOT?";
warning(sTemp);
print(sTemp);
print("Then click 'Yes' to resume and finish the job,"
+ " to delete the new element.");
print("Or, click 'No' to end the job,"
+ " to leave the new node in the AOT.");
pause;
// Cleans up by deleting the newly added element.
tnode2Enum = TreeNode::findNode(
#BaseEnumsPath
+ "\\" + sEnumName
+ "\\" + sEnumElementNameNew
+ "\\" );
if (tnode2Enum)
{
info("Deleting the enum element: ["
+ sEnumElementNameNew
+ "], because the add did work.");
tnode2Enum.AOTdelete();
}
else
{
error("Not deleting the enum element: ["
+ sEnumElementNameNew
+ "], because the add did not work.");
}
}

Output
The output to the Infolog is as follows:
Message (11:16:07 am)
Deleting the enum element: [PiggyBankAccount], because it pre-exists.
AOToString: Path: \Data Dictionary\Base Enums\BankAccountType Layer: usr
Properties of the first child element:
PROPERTIES
Name
Label

#CheckingAccount
#@SYS95020

ConfigurationKey #
EnumValue

#0

ENDPROPERTIES
iMaxEnumValue == 0
iMaxEnumValue == 1
Is the new element displayed in the AOT?
Deleting the enum element: [PiggyBankAccount], because the add did work.

See also

Microsoft Dynamics AX Class Overview


TreeNode Class

MemberFunction Class
MethodInfo Class
ClassBuild Class

Performing File IO with the TextIo Class [AX 2012]


Updated: August 14, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
X++ code performs file input and output (IO) by using the TextIo class. TextIo uses Unicode.

X++ Sample

The following X++ job code sample creates a file and writes to it. Next the code reads from the file, and prints every record to the Infolog.
The use of the FileIOPermission class is also illustrated. FileIoPermission is used to assert that the current method has the authority to call
another method that checks for such authority. For more information, see Code Access Security.
static void Job_File_IO_TextIo_Write_Read(Args _args)
{
TextIo txIoRead,
txIoWrite;
FileIOPermission fioPermission;
container containFromRead;
int xx,
iConLength;
str sTempPath,
sFileName = "Test_File_IO.txt",
sOneRecord;
;
// Get the temporary path.
sTempPath = WINAPI::getTempPath();

info("File is at: " + sTempPath + sFileName);


// Assert permission.
fioPermission = new FileIOPermission
(sTempPath + sFileName ,"RW");
fioPermission.assert();

// If the test file already exists, delete it.


if (WINAPI::fileExists(sFileName))
{
WINAPI::deleteFile(sTempPath + sFileName);
}

// Open a test file for writing.


// "W" mode overwrites existing content, or creates the file.
txIoWrite = new TextIo( sTempPath + sFileName ,"W");
// Write records to the file.
txIoWrite.write("Hello

World.");

txIoWrite.write("The sky is blue.");


txIoWrite.write("");
txIoWrite.write("// EOFile");
// Close the test file.
txIoWrite = null;
// Open the same file for reading.
txIoRead = new TextIo(sTempPath + sFileName ,"R");
// Read the entire file into a container.
containFromRead = txIoRead.read();
// Loop through the container of file records.
while (containFromRead)
{
sOneRecord = "";
iConLength = conLen(containFromRead);
// Loop through the token in the current record.
for (xx=1; xx <= iConLength; xx++)
{
if (xx > 1) sOneRecord += " ";
sOneRecord += conPeek(containFromRead ,xx);
}
info(sOneRecord);
// Read the next record from the container.
containFromRead = txIoRead.read();
}
// Close the test file.
txIoRead = null;
// Delete the test file.
WINAPI::deleteFile(sTempPath + sFileName);
// revertAssert is not really necessary here,
// because the job (or method) is ending.
CodeAccessPermission::revertAssert();
}

X++ Sample Output

The following is the actual Infolog output.


Note

Several spaces between Hello and World are condensed to one space in the output. This occurs because the read method uses a string of one or more space characters as a delimiter of

tokens, and only the tokens are put into the returned container.
Message (14:12:47)
File is at: C:\DOCUME~1\myalias\LOCALS~1\Temp\Test_File_IO.txt
Hello World.
The sky is blue.
// EOFile

See also

Microsoft Dynamics AX Class Overview


TextIo Class
CommaTextIo Class
BinaryIo Class
FileIOPermission Class
TextBuffer Class

Queries in the AOT for Data Access [AX 2012]


Updated: February 8, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
Queries enable you to ask questions about the data in the Microsoft Dynamics AX database and retrieve information. There are two ways to
create queries:

Use the Queries node in the Application Object Tree (AOT) to create static queries using a graphical interface. For more information
about creating queries in the AOT, see How to: Create Queries by using the AOT.

Use the query system classes to create dynamic queries in code. For more information about creating queries in code, see How to:
Create Queries by Using X++.

See also

Query Elements in the AOT


How to: Create Queries by using the AOT
How to: Create Queries by Using X++

Accessing Data [AX 2012]


Updated: March 7, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
Queries enable you to ask questions about the data in the Microsoft Dynamics AX database and retrieve information. There are two ways to
create queries:

Use the Queries node in the Application Object Tree (AOT) to create static queries using a graphical interface. For more information,
see How to: Create Queries by using the AOT.

Use the query system classes to create dynamic queries in code. For more information, see How to: Create Queries by Using X++.

No matter which method that you use to create a query, the query can include a sorting order to sort the information that is returned. It can also
include a range to filter the information that is returned based on your criteria.
A query can return data from multiple data sources. For more information, see How to: Add Multiple Data Sources to a Query.
You can create queries for forms and reports. For more information, see How to: Coordinate Two Forms by Overriding an Event Method.

Paging

When you create a query with X++, you can add paging support to that query. Paging retrieves the results of a query as a collection of one or
more data subsets known as pages. The QueryRun class supports the following types of paging:

Position based paging divides the query result into pages and enables you to display the data records represented by a specified page.

Value based paging uses a page to represent the data records that are currently displayed in a data grid. Use value based paging when
you want an update to a data grid to automatically redisplay the same set of data records.

To enable paging, use the enablePositionPaging and enableValueBasedPaging methods of the QueryRun class. To use paging with a query, the
query cannot have a disabled data source. Also, the value of the FirstOnly property of the data source must be set to No.

See also

Customizing the Query Form


Query Properties
Query System Classes
Using Expressions in Query Ranges

Walkthrough: Creating an AOT Query that has Group


By and Having Nodes [AX 2012]
Updated: August 31, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
In this walkthrough you create Group By and Having nodes under a query in the Application Object Tree (AOT).
The query you create shows the number of customer records for each destination code where there are more than six customers and the
destination code is not equal to Gen_5. If the query you create was represented in standard ANSI SQL, the select query would look like the
following:
select
ct.DestinationCodeId
,count(*)
from
CustTable as ct
where
ct.DestinationCodeId != 'Gen_5'
group by
ct.DestinationCodeId
having
count(*) > 6
order by
1;
Note

In the example of this topic the query has its AllowCrossCompany property set to Yes. This setting means the query does no filtering on company or party.

Create the Query Entry

You create the query in the AOT by the following steps:


1.

Expand AOT > Queries.

2.

Right-click the Queries node, and then click New Query.

3.

In the Properties window, edit the Name property value to be QryGbyHavgRange23.

4.

Set the AllowCrossCompany property to Yes.

5.

Right-click your QryGbyHavgRange23 node, and then click Save to confirm the node and property changes.

6.

Expand the node for your new query, so that you can see its subnodes including its Data Sources subnode.

7.

Proceed to create the subnodes that are described in the table that follows.

Add a Data Source

Next you must add a data source node to your query.


Subnode

Steps

Data

Add the CustTable as a data source.

Sources

Properties window

1.

Right-click Data Sources, and then click New Data Source.


This creates a new node under Data Sources.

2.

Click the new data source node to highlight it.

3.

In the Properties window, set the Table property to CustTable. This


action also changes the value of the Name property.

This query reads data from only one table, the CustTable table.

Add Subnodes Under Data Sources

The following table shows the steps to create each subnode under
AOT > Queries > QryGbyHavgRange23 > Data Sources. The table also shows the Properties window for each subnode.
Subnode

Steps

Properties window

Fields

Add a field under the new CustTable data source node.


1.

Expand the new data source node.

2.

Right-click the Fields node, and then click New > COUNT.

3.

In the Properties window for the new field node, set the Field property to RecId.

ANSI SQL typically uses an asterisk for the count aggregate function. But in Microsoft Dynamics
AX a field must be used, and by convention the RecId field is usually used.

Ranges

Add a range node to exclude one particular value of the DestinationCodeId field. Each range node
applies to the Where clause of the SQL Select statement that is eventually generated.
1.

Right-click the Ranges node, and then click New Range.

2.

Set the Field property to DestinationCodeId.

3.

Set the Value property to != "Gen_5".

Notice that the Value property is set to both a comparison operator and a specific data value.
Inclusion of an operator is optional.

Group

Add a Group By clause. A query cannot have a Having clause unless it also has a Group By clause.

By

For each unique value in the DestinationCodeId field, the query counts all the CustTable records
that share the same DestinationCodeId value with each other. This is accomplished by adding a
group by clause.
1.

Right-click the Group By node, and then click New Field.

2.

In the Properties window, set the Field property to DestinationCodeId.

Implicitly the system adds the group by field to the fields list at run time, so that the group by field is
also returned when the query is run.

Having

Add a Having clause to filter the aggregate values that are generated by the Group By clause. In the
present example, the COUNT(RecId) field contains the aggregate values that are filtered.
1.

Right-click the Having node, and then click New > COUNT.

2.

In the Properties window, set the Field property to RecId.

3.

Set the Value property to > 6.

The value filter is compared against the COUNT aggregate result of each record that otherwise can
be returned. The value is not compared against the RecId field.

Order

Add an Order By node. The order by clause operates on the records that remain after all the filtering

By

is completed.
1.

Right-click the Order By node, and then click New Field.

2.

In the Properties window, set the Field property to DestinationCodeId.

3.

Set the Direction property to Descending.

4.

Right-click the QryGbyHavgRange23 node, and then click Save.

Next is an image of how the finished query looks when it is fully expanded in the AOT:

Note

The preceding screen images were taken from an installation of Microsoft Dynamics AX 2012.

X++ Code to Run the Query

You can use the following X++ code to run the AOT query created in the previous procedure. The code is an X++ job that you can paste into a
new job under AOT > Jobs.
static void QryGbyHavgRange23Job(Args _args) // X++ job.
{
CustTable ct;
Query q = new Query(queryStr(QryGbyHavgRange23));
QueryRun qr = new QueryRun(q);
while(qr.next())
{
ct = qr.get(tableNum(CustTable), 1);
info(strFmt("(Q23) , %1 , %2",
ct.DestinationCodeId, ct.RecId));
}
info("Done.");
}
/*** Infolog display of results:
Message (04:11:40 pm)
(Q23) , Gen_9 , 8
(Q23) , Gen_8 , 11
(Q23) , Gen_7 , 10
(Q23) , Gen_4 , 15
(Q23) , Gen_3 , 8
(Q23) , Gen_2 , 21
(Q23) , , 26
Done.
***/

See also

Queries in the AOT for Data Access

Cross-Company Data Access [AX 2012]


Updated: February 14, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
A cross-company query returns data for several companies in a single run. A query does not have to be limited to returning data for the current
session company. A cross-company query operates over all companies that you have read permissions for, or over a subset of companies that you
specify.

How to Create a Cross-Company Query

To create a cross-company query:

In X++, use the crossCompany keyword on the X++ select statement.

In X++, set the allowCrossCompany property method to true on an instance of the Query class.

In the AOT, set the AllowCrossCompany property to Yes on a node under Query.

Cross-Company Querying in Forms


You can also design cross-company query behavior into dynamically linked parent and child form pairs. One important step in creating such
forms is to set the FormDataSource.crossCompanyAutoQuery to true. Or in the AOT, set the CrossCompanyAutoQuery property to Yes on a
node under the Data Sources of a Form.

Equivalent to Unions

The results returned for an X++ select crossCompany query match what could be returned by a union of several select statements that each
omits the crossCompany keyword.

In the Microsoft Dynamics AX client, you could set your current session company to CM1, then run a select query and save the results. You
could switch to company CM2, rerun the query, and then add the results to the earlier results. You could repeat this cycle for all the companies
you are authorized to see. Your accumulated results would be the same as running one select crossCompany.

In This Section

Cross-Company X++ Code Basics


Cross-Company and the company Getter Method
Cross-Company Queries for Views
Cross-Company Reports in the AOT

See also

Queries in the AOT for Data Access

Cross-Company X++ Code Basics [AX 2012]


Updated: February 20, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
You can create a cross-company query by using X++ code. There are two ways to do this:

crossCompany keyword on the select statement

Query class methods

A cross-company query can also be created under the Query node in the Application Object Tree (AOT).

A cross-company query cannot return data for companies that the user does not have permission to access. A cross-company query can be limited
to a subset of the companies that the user is authorized to access.
The cross-company query is useful if at least one of the tables has the SaveDataPerCompany property set to Yes.

crossCompany Keyword

You can create a cross-company query by using the crossCompany keyword on the X++ select statement. You have the option of adding a
container variable of company identifiers immediately after the crossCompany keyword (separated by a colon). The container restricts the
selected rows to those with a dataAreaId that match a value in the container.
The following code example populates a table buffer with all the BankAccountTable rows that have a dataAreaId of either cm1 or cm2 or dat.
This example assumes that the user has authority to access data for these three companies. The first two dataAreaId values that are found will be
printed.
static void JobDemoCrossCompany(Args _args)
{
BankAccountTable tabBAT; // saveDataPerCompany == true.
container conCompanies = [ 'cm1', 'cm2', 'dat' ];
str 4 sCompanyPrevious = " "; // Maximum length is 4 characters.
int iCountCompanies = 0;
;
while select
crossCompany
: conCompanies
* from tabBAT
order by dataAreaId
{
if ( sCompanyPrevious != tabBAT.dataAreaId )
{
info( tabBAT.dataAreaId + " = tabBAT.dataAreaId" );
iCountCompanies++;
if ( iCountCompanies >= 2 )
{
break;
}
sCompanyPrevious = tabBAT.dataAreaId;
}
}
return;
}

Query Class

In X++ code you can use the Query .allowCrossCompany property method to achieve the same result as you can with the crossCompany
keyword on a select statement. The calls to the Query .addCompanyRange method are the same as appending a container of companies to the
crossCompany keyword.
You cannot perform data source level filtering by company in a cross-company query. This is why the call to qbds3 .company is commented out
in the following code example.
static void JobDemoAllowCrossCompany(Args _args)
{
BankAccountTable tabBAT; // saveDataPerCompany == true.
Query qry2;
QueryBuildDataSource qbds3;
QueryRun qrun4;
str sCompanyPrevious = " ";
int iCountCompanies = 0;
int iTableNumBAT;
;
qry2 = new Query();
qry2.allowCrossCompany( true );
qry2.addCompanyRange( 'dat' );
qry2.addCompanyRange( 'twf' );

iTableNumBAT = tableNum( BankAccountTable );

qbds3 = qry2 .addDataSource( iTableNumBAT );


//qbds3.company( 'dat' );

qrun4 = new QueryRun( qry2 );

while ( qrun4.next() )
{
if ( qrun4.changed( iTableNumBAT ) )
{
tabBAT = qrun4.get( iTableNumBAT );

if ( sCompanyPrevious != tabBAT.dataAreaId )
{
print( tabBAT.dataAreaId + " = tabBAT.dataAreaId" );
iCountCompanies++;
if ( iCountCompanies >= 2 )
{
break;
}
sCompanyPrevious = tabBAT.dataAreaId;
}
}
}
pause;
return;
}

Query in the AOT

In the AOT, you can get cross-company functionality from a query node by setting the AllowCrossCompany property to Yes (the equivalent of
true in X++ code). You can override methods on the node of your query to call the Query.addCompanyRange method.
For more information, see Cross-Company Reports in the AOT.

See also

Cross-Company Data Access


DataArea Table

Cross-Company Data Modification Using X++ [AX


2012]
Updated: February 13, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
You can use a while select crossCompany statement for cross-company data modification. You may need to use this statement because you
cannot use the crossCompany keyword in X++ SQL statements that modify data nor can you use sub-select commands embedded in data
modification statements. You can issue a while select crossCompany statement first, and then use the populated table buffer to drive data
modification commands. The changeCompany keyword is a central part of this technique.

Data Modification Options

In X++, you can modify data with either SQL statements or with methods on a table buffer. The SQL statements are best for modifying a set of
rows with one command. The methods are used to modify one row per call.
The SQL data modification statements are:

delete_from

insert_recordset

update_recordset

The data modification methods on a table buffer variable are inherited from the xRecord class. These methods are:

delete

insert

update

All of these options can be used in cross-company data modification processing.

delete_from Command

In X++ code, you can delete data on a cross-company basis, even though you cannot use the crossCompany keyword on the delete_from
statement. The following code example shows one way you can do this.
static void JobCCDel( Args _args )
{
Table21 tab21a , tab21b;
;
ttsBegin;
while select
crossCompany
minof( ratingNum )
, dataAreaId
from
tab21a
group by
dataAreaId
{
changeCompany( tab21a .dataAreaId )
{
tab21b = null;
delete_from tab21b
where tab21b .ratingNum == tab21a .ratingNum;
}
}
ttsCommit;
}

insert Method

The following X++ code example shows how to use the cross-company feature for inserting data, even though the crossCompany keyword
cannot be used on the insert_recordset command.
static void JobCCIns( Args _args )
{
Table21 tab21;
Table22 tab22;
;
ttsBegin;
while select
crossCompany
actionDate , name , dataAreaId
from
tab21
where
tab21 .actionDate > str2Date( '1998-01-22' , 321 )
{
changeCompany( tab21 .dataAreaId )
{
tab22 = null;
tab22 .actionDate = tab21 .actionDate;
tab22 .name = tab21 .name;
tab22 .insert();
}
}
ttsCommit;
}

update_recordset with forUpdate on select

This X++ example uses the forUpdate keyword on the while select crossCompany statement. Only one table buffer variable is declared. This
example also uses the update method on the table buffer.
static void JobCCForUpdMethod( Args _args )
{
Table21 tab21;
;
ttsBegin;
while select
forUpdate crossCompany
countOfReviews
from
tab21
{
changeCompany( tab21 .dataAreaId )
{
tab21 .countOfReviews = tab21 .countOfReviews + 2;
tab21 .update();
}
}
ttsCommit;
}

Cross-Company Methods and Properties [AX 2012]


Updated: February 9, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
In X++ code, you can call functions that are related to cross-company functionality by using:

Query class methods

changeCompany X++ keyword

In X++ code, you can set properties that are related to cross-company functionality by using:

allowCrossCompany on a Query instance

company on a table buffer (extended from xRecord class)

crossCompanyAutoQuery on a FormDataSource instance

Just as these properties can be set in X++ code, they can also be set in the Application Object Tree (AOT). These methods can be called in
methods overridden in the AOT.

Functions

Methods on the Query class


In X++ code, after you create an instance of the Query class, you can call several instance methods that are related to cross-company
functionality. These query methods are relevant only if you set the query's allowCrossCompany property to true:

addCompanyRange

clearCompanyRange

getCompanyRange

If you do not call addCompanyRange, the query returns data for all companies that the user has authority to read. You can call
addCompanyRange to restrict the range of company data that the query returns. The first call to addCompanyRange minimizes the data that the
query returns because data is returned for only the first company that is added. Subsequent calls to addCompanyRange increase the amount of
data returned by the query.
The clearCompanyRange method cancels the earlier calls to addCompanyRange. The clearCompanyRange method has no effect if
addCompanyRange has not been called.
The getCompanyRange method returns a container of dataAreaId values that have been added.

changeCompany Keyword

The X++ language has a keyword changeCompany. You use changeCompany to create a bracketed scope in which the active company can
differ from your session company.
The keyword changeCompany is used in data modification processing in cross-company scenarios.
For more information about how to use changeCompany for data modification in cross-company scenarios, see Cross-Company Data
Modification Using X++.
For more information about how to use the changeCompany keyword beyond cross-company processes, see Change Company Design Pattern.

Properties

There are properties you can set that are related to cross-company functionality. In X++ these can be either properties or property methods
(which are small methods that get and set a state of the object). In the AOT, these appear in the Properties window.

AllowCrossCompany Property on Query


In the AOT, each query node has the AllowCrossCompany property. The default value is No. You can set this property to Yes to make the query
return data for all companies that you are authorized to read from.
This is the same property that can be accessed in X++ code on an instance of the Query class.

Company Property on xRecord Buffers


In X++ code, a buffer variable can be declared for a table. For the BankAccountTable, the buffer declaration could be: BankAccountTable
myBat;. The myBat variable inherits all the methods and properties from the xRecord class.
One of the properties inherited by a table buffer is company. In X++, the syntax is a pair of get and set property methods (the setter takes a
parameter).
In the AOT, this property is not present on tables that are immediately under the Tables node. But when a table is dragged onto a query's Data
Sources node, that new table node has the Company property. The default setting is blank.
This Company property must be left blank when the AllowCrossCompany property is set to Yes.

Purpose of Setting the Company Property


When AllowCrossCompany is No, you can set a data source's Company property to a non-blank value to alter the current company context, as
an override to the current session company. This is similar to using the changeCompany keyword in X++ code, although the scope or duration
of the change is different.
You can set Company to a value to automate agreements between two companies. For example, the creation of a purchase order might
automatically generate an invoice for the other company.

See also

Cross-Company X++ Code Basics

Cross-Company and the company Getter Method [AX


2012]
Updated: June 7, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
The dataAreaId value returned by the company getter method on table buffer variables can differ between cross-company versus single-company
scenarios.
For information about how a table buffer variable inherits company from the xRecord class, see Cross-Company Methods and Properties.
Tables can be categorized into the following types:

Global - The SaveDataPerCompany property is set to No.

Company-specific - The SaveDataPerCompany property is set to Yes.

Shared - Company-specific tables associated with a virtual company.

These different types of tables interact differently with the cross-company feature. In cross-company scenarios, the current company can be
different from the company of the row currently being processed by the application X++ code. This difference has implications for the company
getter method.
Note

The current company (the user's session company) is shown in the status bar in the lower-right portion of the Microsoft Dynamics AX client window.

Global Tables and the company Method

For a table buffer variable declared from a global table, the company getter method returns the user's session company. Global tables do not have
the field named dataAreaId.

Company-Specific Tables and the company Method

A table buffer variable declared from a company-specific table can be populated by a while select crossCompany statement. This populates the
buffer with rows that represent a variety of companies. When a buffer is populated in this manner, the company method returns the dataAreaId
value of the buffer's current row, regardless of the user's session company.

Shared Tables and the company Method

For some rows in a shared table, the dataAreaId field can have a value representing the virtual company that the table is associated with. Other
rows can have dataAreaId values for real companies that are outside of the virtual company.
The following X++ code example populates the table buffer with a row set from a shared table that has both kinds of dataAreaId values.
while select crossCompany * from SH_buffer { /* X++ */ }

The following descriptions assume that the shared table is associated with virtual company VC9. The descriptions assume that VC9 is associated
with real companies CM1 and CM2.
During the while select loop that processes rows of each dataAreaId value, the company getter method on the table buffer returns values
according to the following table.
Test case number

dataAreaId in shared table's current row

Current session company

Returned by company getter method

VC9

CM1

CM1

VC9

CM2

CM2

VC9

CM3

Either CM1 or CM2, whichever the user has greater permissions on.
For example, Delete permission is greater than Read permission.

CM3

(Any company)

CM3

Note

In Microsoft Dynamics AX 2009 the above table describes the behavior when either a table or a view is the subject of the while select. In the previous version, it applied to tables but
not to views.

Rules Governing the company Method

The following rules govern the behavior of the company getter method of table buffer objects:

The session company can never be a virtual company.

The company method never returns a value that conflicts with the dataAreaId of the current row. The dataAreaId takes precedence over
the session company.

The company method never returns the dataAreaId value of a virtual company. Instead, a real company in the virtual company is
returned.

When the current row has the dataAreaId of a virtual company, the company method returns one of the real companies in the virtual
company.

After the clear method is called on a table buffer, the company getter method retrieves the current company of the client. However, this
is not true for temporary tables.

Greater Permissions Factor for Test Case 3


Test case number 3 in the preceding table shows that sometimes the system chooses which real company to return when the company method is
called. In cases where the session company is not part of the current row's virtual company, the company method returns whichever real
company the user has the most permissions for.
In test case 3, if the user has both read and insert permission for CM1, but only read permission for CM2, then CM1 is returned.
The system determines which real company the user has greater permissions for only when the session company is not in the virtual company.

See also

Best Practices for Table Collections


Table Properties
xRecord.company Method
true

Cross-Company Queries for Views [AX 2012]


Updated: February 20, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
In the Application Object Tree (AOT), you can build a view by dragging a query node onto the Data Sources node of your view. The query
could have the AllowCrossCompany property set to Yes. However, this will not return cross-company results from the view.
To return cross-company results from a view, you need to use the crossCompany keyword on the select statement that reads from the view. The
AllowCrossCompany setting on the view's data source query is ignored in X++ select statements that read from a view.

See also

Cross-Company X++ Code Basics

Cross-Company Reports in the AOT [AX 2012]


Updated: February 20, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
You can use the Application Object Tree (AOT) to create a cross-company report. The simplest way to create a report is to set the
AllowCrossCompany property to Yes on your query. Then drag the query node onto your report's Data Sources node.
To fully control the cross-company behavior of an AOT query or report, you must understand the relationships between:

AOT query node

Query class

QueryRun class

For basic information about cross-company queries, see Cross-Company X++ Code Basics.

Relationships between AOT, Query, and QueryRun

The properties of an AOT query node match the Query class. The methods available for override on a query node match the QueryRun class.
The QueryRun class has a property method named query, which is the query instance it will run. You can access this QueryRun .query property
in methods that you override on the Queries node of the AOT. This enables you to control the details of the cross-company behavior at run time.

AllowCrossCompany Property

In the AOT, query node objects have the AllowCrossCompany property listed in the Properties window. For new queries the default value is
No (which is equivalent to false in X++ code). To make a query cross-company you need to set AllowCrossCompany to Yes.
The classes QueryRun and Query both have the AllowCrossCompany property, but their values always equal each other. When you read
AllowCrossCompany from QueryRun, QueryRun reads it from Query. When you set AllowCrossCompany on QueryRun, it sets in on Query.
Note

Although the QueryRun class and Query classes both have the allowCrossCompany property, only the Query class has the cross-company methods such as addCompanyRange.

Company Range Methods in AOT Reports

You can override methods on the AOT report node to control the details of cross-company behavior. For example, you could override the report's
init method with the following X++ code.
public void init()
{
super();
this.query().allowCrossCompany( true );
this.query().addCompanyRange( "dat" );
this.query().addCompanyRange( "dmo" );
}

See also

MorphX Reporting Tools

How to: Add Multiple Data Sources to a Query [AX


2012]
Updated: December 13, 2011
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
You can add parent and child data sources to a query.
Note

If you add data sources at the same level, separate SQL statements are executed sequentially.

To manage changes to AOT objects, a version control system is available. For more information, see Version Control System.
Add multiple data sources to a query
1.

In the Application Object Tree (AOT), click Queries, locate the query you want to add data sources to, and then click the query node.
For information about create queries, see Accessing Data.

2.

Right-click Data Dictionary, and then click Open New Window.

3.

Drag a table, map, or view from the new window to the Data Sources node below the query node to add a parent data source.

4.

Click the parent data source, and then drag a table, map, or view from the new window to the Data Sources node below the parent
data source to add a child data source.

5.

Specify how the parent and child data sources are joined by setting the JoinMode property on the child data source

6.

Create a relationship between the data sources. This information is provided later in the topic.

The following table describes the available values for the JoinMode property.
Value

Description

InnerJoin

Combines records from two data sources whenever there are matching values in a common field.
For example, if you selected the records that show orders placed by each customer, the query would select only records for customers who placed orders.

OuterJoin

Joins all the records in one data source even if there are no matching values in the joined field from the second data source.
This allows you to return records that do not have a corresponding match in the joined table. For example, data is required from all employees and their respective
departments from the Employee table. As long as all employees are assigned to a department, an InnerJoin works. However, the president of the company does not
have a department, and an inner join between the tables will not retrieve this data. The solution to this kind of problem is an outer join.

ExistsJoin

Combines records from one data source whenever there a value exists in a common field in another data source.
ExistsJoins are like InnerJoin, but MorphX uses only the embedded data source as a condition. Thus, the records in the embedded data source are not fetched by the
query. The query will fetch the records in the primary data source only if a match is made with the embedded data source.

NoExistsJoin

Selects records from one data source whenever a value in a common field in another data source does not exist. The opposite of ExistsJoin.

Create a Relationship Between the Data Sources

Set the Relations property to Yes on the child data source.


-or-

Add a relation by doing the following:


1.

Set the Relations property to No on the child data source.

2.

Right-click the Relations node, and then click New Relation.

3.

Select a field from the parent data source in the Field property.

4.

Select a field from the child data source in the RelatedField property.

5.

Save all modifications.

See also

Customizing the Query Form


Query Properties
Using Expressions in Query Ranges

Customizing the Query Form [AX 2012]


Updated: February 3, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
The Query form is displayed prior to a query being run and enables users to change the elements of a query. Use the Query form to do the
following:

Modify data sources.

Specify ranges.

Define a sort order.

Save the query.

By default, the Query form is the SysQueryRun form that's specified by a query's Form property. To implement your own Query form, create a
form, and then set the Query.Form property to the name of the custom form.

Display the Query Form from the Application Object Tree

1.

Navigate to the Queries node.

2.

Right-click the query, and then select Open.

The Query form uses the SysQueryRun application class, which extends the QueryRun kernel class.

Display the Query Form from Code

Display the Query form from code by using the QueryRun.prompt method. The following example instantiates the SalesQuotationUpdate query,
displays the Query form by calling the prompt method, and then iterates through the returned records.
static void RunSalesQuotationUpdate(Args _args)
{
QueryRun

SalesQuotationUpdate;

SalesQuotationTable SalesQuotationTable;
;
SalesQuotationUpdate = new QueryRun(QueryStr(SalesQuotationUpdate));
if (SalesQuotationUpdate.prompt())
{
while (SalesQuotationUpdate.next())
{
if (SalesQuotationUpdate.changed(tablenum(SalesQuotationTable)))
{
SalesQuotationTable = SalesQuotationUpdate.get(
tablenum(SalesQuotationTable));
info(SalesQuotationTable.QuotationId);
}
}
}
}

Customize the Query Form

Customize the Query form by calling methods that are available from the SysQueryRun class. The following table describes the options that can
be set for the Query form.
Option

When the value is set to

Default

Allows the user to add a child data source.

SysQueryRun.promptAllowAddDataSource

true

(true);

Allows the user to add a range.

SysQueryRun.promptAllowAddRange
(QueryAllowAdd::AllFields);

Allows the user to add a sort order.

SysQueryRun.promptAllowAddSorting
(QueryAllowAdd::AllFields);

QueryAllowAdd::
AllFields

QueryAllowAdd::
AllFields

Allows the user to save or delete the query.

SysQueryRun.promptAllowSave(true);

true

Displays and loads the Query form with the query that was last run, its data sources, ranges, and sort orders.

SysQueryRun.promptLoadLastUsedQuery

true

(true);

Allows queries to be saved for each user. Users can also delete their own saved queries.

SysQueryRun.promptSaveQueryPrUser

true

(true);

Allows users to change and save their queries. If false, the user cannot change or save a query.

Query.userUpdate(true);

true

Displays the Query form's Select query combo box.

SysQueryRun.promptShowQuerySelect

true

(true);

Displays the Reset button, which sets all the data sources, ranges, and sort orders to their original states.

SysQueryRun.ShowReset(true);

true

Displays the Sorting tab.

SysQueryRun.promptShowSorting

true

(true);

See also

Query Elements in the AOT


Accessing Data
How to: Create Queries by Using X++

How to: Create Queries by using the AOT


Query Object Model

Query Record Retrieval Sequence [AX 2012]


Updated: February 3, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
When a query is designed in the Application Object Tree (AOT), it can access data from multiple data sources. These data sources can be created
at the same level as each other or nested in a parent-child relationship. The sequence of the retrieved records depends on how the data sources
are linked.

Outer Joins

If a single data source is nested as shown in the following figure and the JoinMode property is set to OuterJoin, the records are fetched in the
following sequence:

A1, B1, A2, B2, A3, B3,An, Bn

A data source with a single child data source


If more than one data source is nested, the child data sources are at the same level as shown in the following figure. The JoinMode property is set
to OuterJoin, and the records are fetched in the following sequence:
A1, B1...Bn, C1Cn, A2,An, B1Bn, C1Cn

A data source with multiple child data sources

Inner Joins

If nested data sources have an inner join, records are fetched in the following sequence:

A1, B1, C1, A2, B2,An, Bn, Cn

Exists Joins

If nested data sources have an exists join, records are only fetched from the primary data source as follows:

A1, A2, A3, A4An

See also

How to: Add Multiple Data Sources to a Query


Query Properties

How to: Create Queries by Using X++ [AX 2012]


Updated: July 13, 2012
Applies To: Microsoft Dynamics AX 2012 R3, Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft
Dynamics AX 2012
In Microsoft Dynamics AX, you can create a query to retrieve data by using the query classes. For more information, see Query Object Model.
In addition, by using X++ code, you can create a query and then save that query to the Application Object Tree (AOT).
You can also create a query by using the AOT. For more information, see How to: Create Queries by using the AOT.

Create a Query by Using X++

1.

Add a class to the AOT. For more information about adding a class, see Declaration of Classes.

2.

Add a class method that creates a query by using the Query system classes.
In the following example, the QueryRun class runs the query specified by the q object. The addDataSource method specifies
CustTable as the data source for the query. The addRange and value methods specify account numbers between 4000 and 4022. The
addSortField method specifies that data is sorted on the DlvMode field.
public void runMyDynamicQuery2()
{

Query q;
QueryRun qr;
QueryBuildDataSource qbd;
QueryBuildRange qbr;
q = new Query();
qbd = q.addDataSource(TableNum(CustTable));
qbr = qbd.addRange(FieldNum(CustTable, AccountNum));
qbr.value(">=4000"); // Default operator is ==.
qbr = qbd.addRange(FieldNum(CustTable, AccountNum));
qbr.value("<=4022");
qbd.addSortField(FieldNum(CustTable, DlvMode));
qr = new QueryRun(q);
qr.prompt();
pause;
}

Access the Query by Using a Menu Item

1.

Add a main method to the class, and call the method that you created in step 2.

2.

Create an action menu item to reference the class by clicking Menu Items, right-clicking Action, and then clicking New Menu Item
in the AOT.

3.

Right-click the menu item, click Properties, and set ObjectType to Class. Then select the class that you created in step 1 from the
Object property list.
You can include the menu item in forms and reports by configuring form and report controls to reference the menu item. For more
information, see Form Control Properties.

4.

Add your menu item to a menu.


For example, expand AOT > Menus > SystemAdministration > Common, and then right-click New > Menu item. Fill in the
properties of the new menu item node.

Create a Query in the AOT by Using X++

The following procedure is a job that you can run in the AOT to create a query called MyQuery1, provided MyQuery1 does not already exist in
the Queries node.
1.

In the AOT, right-click Jobs, and then click New Job. The Code editor window opens.

2.

In the Code editor window, copy the following code, and then paste it in the Code editor.
static void CreateQuery6Job(Args _args)
{
TreeNode
Query

treeNodeObj;
queryObj; // Extends TreeNode class.

QueryBuildDataSource qbds;
QueryBuildRange
QueryRun
CustTable
str

qbr;
qr;
xrecCustTable;

queryName = "MyQuery1";

// Macro.
#AOT
// Delete the query from the AOT, if the query exists.
treeNodeObj = TreeNode::findNode(#QueriesPath);
treeNodeObj = treeNodeObj.AOTfindChild(queryName);
if (treeNodeObj) { treeNodeObj.AOTdelete(); }
// Add the query to the AOT.
treeNodeObj = TreeNode::findNode(#QueriesPath);
treeNodeObj.AOTadd(queryName);

queryObj = treeNodeObj.AOTfindChild(queryName);

// Further define the query.


qbds = queryObj.addDataSource(tablenum(CustTable));
qbr = qbds.addRange(fieldnum(CustTable, DlvMode));
qbr.value(">10");
// Compile the query.
queryObj.AOTcompile(1);
queryObj.AOTsave();
// Run the query.
qr = new QueryRun("MyQuery1");
while ( qr.next() )
{
xrecCustTable = qr.GetNo(1); // 1 means first data source.
Global::info(strFmt("%1 , %2",
xrecCustTable.AccountNum, xrecCustTable.DlvMode));
}
// Delete the query from the AOT.
treeNodeObj = TreeNode::findNode(#QueriesPath);
treeNodeObj = treeNodeObj.AOTfindChild(queryName);
treeNodeObj.AOTdelete();
}

3.

Press F7 to compile, and then press F5 to run the job. A query named MyQuery1 is created in the Queries node. The query is run, and
then is deleted.

SysQueryRangeUtil Class has Incompatibilities with .NET CIL

In your X++ code, you can use certain methods of the SysQueryRangeUtil class to build query range values that are resolved during run time.
One such method is SysQueryRangeUtil::currentWorker(), which is shown in the following code snippet.
QueryBuildRange myQueryBuildRange;
//... (More X++ code here) ...
myQueryBuildRange.value(queryValue(SysQueryRangeUtil::currentWorker()));
However, if your X++ code is compiled to .NET Framework CIL, and is then run as CIL, your code might cause an error.

See also

Accessing Data
Customizing the Query Form
Using Expressions in Query Ranges
How to: Link Two Forms by Using Dynamic Links

You might also like