For creating a batch class in Dynamics AX we can start from the Tutorial_RunbaseBatch class, but here is the explanation for understanding all its methods:
In the classDeclaration, we declare any variable that contains user's selection or preferences (for example, the customer account for launch a customer report). Also, we declare other variables like dialog fields, auxiliar variables, etc. But, the most important feature here, is the #localmacro.CurrentList declaration. This macro helps you to define which variables you want to save for running the class in batch mode (when not user interaction is available).
class Tutorial_RunbaseBatch extends RunBaseBatch
{
// Packed variables
TransDate transDate;
CustAccount custAccount;
// Dialog fields
DialogField dlgCustAccount;
DialogField dlgTransDate;
// Current version
// We can have different versions for different purposes
#define.CurrentVersion(1)
#define.Version1(1)
#localmacro.CurrentList // Our current variable list for save user's selected values
transDate,
custAccount
#endmacro
}
The macro #define.CurrentVersion(1) and #define.Version1(1) are useful for scaling our class when we need to change/upgrade it preserving compatibility.
Now two methods: pack and unpack. These methods are used for store and retrieve user's preferences and perform the batch operation when none user are available (in batch mode). Here is the point where we use the macro defined previously:
public container pack()
{
return [#CurrentVersion,#CurrentList];
}
public boolean unpack(container packedClass)
{
Version version = RunBase::getVersion(packedClass);
;
switch (version)
{
case #CurrentVersion:
[version,#CurrentList] = packedClass;
break;
//case #otherVersion:
//[version,#CurrentList, #otherList] = packedClass;
//break;
default:
return false;
}
return true;
}
Bacause we need to ask the user about preferences for run this object (report, process, query, etc.), we must implement some methods:
- dialog: for build the custom dialog for prompting user's preferences.
- dialogPostRun: after dialog was created, you can perform other UI tasks here.
- getFromDialog: used for retrive user's preferences (dialog values).
- validate: here, you can perform a validation for any data entered by the user.
public Object dialog()
{
DialogRunbase dialog = super();
;
// Creation of our custom dialog fields/controls to ask user for preferences
dlgTransDate = dialog.addFieldValue(typeid(TransDate),transDate);
dlgCustAccount = dialog.addFieldValue(typeid(CustAccount),custAccount);
return dialog;
}
public void dialogPostRun(DialogRunbase dialog)
{
;
super(dialog);
}
public boolean getFromDialog()
{
;
// Retrieving user's preferences
transDate = dlgTransDate.value();
custAccount = dlgCustAccount.value();
return super();
}
public boolean validate()
{
// We can perform some validations here
if (false)
return checkFailed("");
return true;
}
Finally, the main method constructs the object from this batch class, and after prompting user and validation was successful, the run method is called to perform some task (in batch mode if it was selected):
server static Tutorial_RunbaseBatch construct()
{
return new Tutorial_RunbaseBatch();
}
public void run()
{
try
{
// Obviously, this code is silly, why show something to nobody?
// remember, this code is running in batch without user interaction
info(strfmt("Parameters: %1 for %2", transDate, custAccount));
}
catch(Exception::Deadlock)
{
retry;
}
catch(Exception::UpdateConflict)
{
throw Exception::UpdateConflict;
}
catch
{
throw Exception::Error;
}
}
static void main(Args args)
{
Tutorial_RunbaseBatch tutorial_RunBase;
;
// Instanciating this batch class
tutorial_RunBase = Tutorial_RunbaseBatch::construct();
// Prompting user and run if all is ok
if (tutorial_RunBase.prompt())
tutorial_RunBase.run();
}
In the classDeclaration, we declare any variable that contains user's selection or preferences (for example, the customer account for launch a customer report). Also, we declare other variables like dialog fields, auxiliar variables, etc. But, the most important feature here, is the #localmacro.CurrentList declaration. This macro helps you to define which variables you want to save for running the class in batch mode (when not user interaction is available).
class Tutorial_RunbaseBatch extends RunBaseBatch
{
// Packed variables
TransDate transDate;
CustAccount custAccount;
// Dialog fields
DialogField dlgCustAccount;
DialogField dlgTransDate;
// Current version
// We can have different versions for different purposes
#define.CurrentVersion(1)
#define.Version1(1)
#localmacro.CurrentList // Our current variable list for save user's selected values
transDate,
custAccount
#endmacro
}
The macro #define.CurrentVersion(1) and #define.Version1(1) are useful for scaling our class when we need to change/upgrade it preserving compatibility.
Now two methods: pack and unpack. These methods are used for store and retrieve user's preferences and perform the batch operation when none user are available (in batch mode). Here is the point where we use the macro defined previously:
public container pack()
{
return [#CurrentVersion,#CurrentList];
}
public boolean unpack(container packedClass)
{
Version version = RunBase::getVersion(packedClass);
;
switch (version)
{
case #CurrentVersion:
[version,#CurrentList] = packedClass;
break;
//case #otherVersion:
//[version,#CurrentList, #otherList] = packedClass;
//break;
default:
return false;
}
return true;
}
Bacause we need to ask the user about preferences for run this object (report, process, query, etc.), we must implement some methods:
- dialog: for build the custom dialog for prompting user's preferences.
- dialogPostRun: after dialog was created, you can perform other UI tasks here.
- getFromDialog: used for retrive user's preferences (dialog values).
- validate: here, you can perform a validation for any data entered by the user.
public Object dialog()
{
DialogRunbase dialog = super();
;
// Creation of our custom dialog fields/controls to ask user for preferences
dlgTransDate = dialog.addFieldValue(typeid(TransDate),transDate);
dlgCustAccount = dialog.addFieldValue(typeid(CustAccount),custAccount);
return dialog;
}
public void dialogPostRun(DialogRunbase dialog)
{
;
super(dialog);
}
public boolean getFromDialog()
{
;
// Retrieving user's preferences
transDate = dlgTransDate.value();
custAccount = dlgCustAccount.value();
return super();
}
public boolean validate()
{
// We can perform some validations here
if (false)
return checkFailed("");
return true;
}
Finally, the main method constructs the object from this batch class, and after prompting user and validation was successful, the run method is called to perform some task (in batch mode if it was selected):
server static Tutorial_RunbaseBatch construct()
{
return new Tutorial_RunbaseBatch();
}
public void run()
{
try
{
// Obviously, this code is silly, why show something to nobody?
// remember, this code is running in batch without user interaction
info(strfmt("Parameters: %1 for %2", transDate, custAccount));
}
catch(Exception::Deadlock)
{
retry;
}
catch(Exception::UpdateConflict)
{
throw Exception::UpdateConflict;
}
catch
{
throw Exception::Error;
}
}
static void main(Args args)
{
Tutorial_RunbaseBatch tutorial_RunBase;
;
// Instanciating this batch class
tutorial_RunBase = Tutorial_RunbaseBatch::construct();
// Prompting user and run if all is ok
if (tutorial_RunBase.prompt())
tutorial_RunBase.run();
}