Background
This is an article I wrote ages ago, originally published on Axaptapedia, which no longer exists. I found the original in my archive and thought it was worth sharing as a blog, as most of it remains relevant for Dynamics 365 Finance and Operations. I've made minor edits and removed deprecated elements from the original, written for Axapta 4.0.
Okay, enough of that. Let's start!
Introduction
The RunBaseBatch
class extends the RunBase
class and allows creating classes (jobs) that can be added to the batch queue. Once added, the batch server executes the job, a process known as batch processing.
Input Data Parameters
Typically, a class contains logic without a graphical user interface. As RunBaseBatch
inherits from RunBase
, it uses the dialog framework to prompt users for input parameters interactively. These parameters are class member variables added to the dialog box. The control type depends on the extended data type used. For example, properties like Auto
, Combo box
, or Radio button
can be set on Base enums via the Extended Data Type.
A boolean variable creates a checkbox, an enum a combo box, and a string a text edit control. Each dialog control corresponds to a class variable used to set and retrieve values, persisting them for batch execution. Controls are usually added in code during runtime, requiring a different approach to override methods compared to standard forms. Alternatively, an existing dialog from the AOT can be used for greater control, similar to a standard form.
Parameters enhance job flexibility and reusability, allowing different behaviors based on selections. For instance, a log cleanup job might accept a "days" parameter to delete records older than a user-specified value (e.g., 30 days).
Persistence
Parameters, as class variables, are persisted in the database via the SysLastValue
framework. They are packed when the job is queued and unpacked when executed by the batch server. Variables must be listed in a local macro, and the class must override the pack
and unpack
methods, as RunBaseBatch
implements the SysPackable
interface.
The pack
method is called when a job is queued, and unpack
before execution. During batch execution, only new
, unpack
, and run
methods are called, as no user interaction occurs. The run
method should contain the core logic.
Query
RunBaseBatch
supports queries for data selection. If the queryRun
method is overridden, the dialog automatically displays query ranges and values. Users can modify the query via a "Select" button, adding or removing ranges, joining related tables, or changing sort order. For reusable queries, create them in the AOT rather than in code.
Operation Progress
For time-consuming operations, a progress bar is recommended. The RunBase
framework's Operation Progress
functionality, inherited by RunBaseBatch
, can be implemented in the run
method to display progress.
Making the Class Runnable
A class is not executable by default. To make it runnable, add a static main
method with an Args
parameter. The kernel calls this method interactively, passing an Args
object containing properties like an active buffer or caller reference. This supports constructor-based object-oriented design and enables access via menu items from the main menu or forms.
Considerations
New Method
As RunBaseBatch
classes can run in batch journals, the new
method should have no arguments to avoid stack trace errors during batch journal setup.
Version Number
Class variables are listed in a local macro for persistence. A version number tracks changes to the variable list, starting at 1 and incrementing with changes. The unpack
method must handle versioning to prevent errors when the persisted variable list size mismatches the macro list.
Methods
new
Creates a new class instance. Called during batch execution.
pack
Persists class variables using a local macro. Called when the dialog is closed with "OK".
unPack
Re-instantiates class variables from the macro. Called before run
in batch execution.
dialog
Adds controls to the dialog box, setting values from corresponding class variables.
getFromDialog
Assigns class variable values from dialog controls.
validate
Validates input parameters, displaying an info log for invalid inputs.
run
The central method containing the class's core logic. Called during batch execution.
initParmDefault
Initializes macro list variables when unPack
returns false (no usage data found).
queryRun
Returns a queryRun
object if the class uses a query.
canGoBatchJournal
Indicates if the class can be included in a batch journal. Default is false
.
canGoBatch
Indicates if the class can run in batch. Adds a "Batch" tab to the dialog if true
. Default is true
.
runsImpersonated
Determines if the job runs under the submitting user’s or batch user’s account. Uses runAs
if true
. Default is false
.
description (static)
Returns the class description, displayed in the batch list and dialog title.
caption
Overrides the base class description for the batch list and dialog title.
Creating a Basic Batch Job Step by Step
Create a Class
From the AOT, create a class extending RunBaseBatch
:
public class AV_RunbaseBatchDemo extends RunBaseBatch { }
Class Declaration
Add the following to the class declaration:
public class AV_RunbaseBatchDemo extends RunBaseBatch { NoYes displayMessage; Description message; DialogField fieldDisplayMessage; DialogField fieldMessage; #define.CurrentVersion(1) #localmacro.CurrentList displayMessage, message #endmacro }
Override the pack Method
public container pack() { return [#CurrentVersion, #CurrentList]; }
Override the unpack Method
public boolean unpack(container _packedClass) { Integer version = RunBase::getVersion(_packedClass); switch (version) { case #CurrentVersion: [version, #CurrentList] = _packedClass; break; default: return false; } return true; }
Create the description Method
This sets the batch queue description and dialog caption:
public static ClassDescription description() { return 'Runbase batch demo'; }
Create the construct Method
public static AV_RunbaseBatchDemo construct() { return new AV_RunbaseBatchDemo(); }
Override the initParmDefault Method
public void initParmDefault() { super(); displayMessage = NoYes::Yes; message = 'Hello World!'; }
Override the dialog Method
protected Object dialog() { DialogRunbase dlg; dlg = super(); fieldDisplayMessage = dlg.addFieldValue(typeId(NoYes), displayMessage, 'Display message', 'Indicates whether to display a message or not.'); fieldMessage = dlg.addFieldValue(typeId(Description), message, 'Message', 'The message to display'); return dlg; }
Override the getFromDialog Method
public boolean getFromDialog() { boolean ret; ret = super(); displayMessage = fieldDisplayMessage.value(); message = fieldMessage.value(); return ret; }
Override the run Method
public void run() { if (displayMessage) { info(message); } }
Create the static main method to make the class runnable.
public static void main(Args _args) { AV_RunbaseBatchDemo rb = AV_RunbaseBatchDemo::construct(); if (rb.prompt()) { rb.run(); } }
No comments:
Post a Comment