Dev Notes

Running Batch Jobs in X++

Batch jobs are the backbone of any D365FO implementation. This post walks through two approaches: the legacy RunBase pattern and the modern SysOperation framework.

RunBase pattern

The RunBase class is the classic way to build a batch-capable process. It handles the dialog, packing/unpacking parameters for the batch queue, and progress updates.

class MyBatchJob extends RunBase
{
    // Parameters stored for batch execution
    CustAccount custAccount;

    public boolean canGoBatch()
    {
        return true;
    }

    public Object dialog()
    {
        DialogField fldCustAccount;
        Dialog       dlg = super();

        fldCustAccount = dlg.addField(extendedTypeStr(CustAccount));
        return dlg;
    }

    public boolean getFromDialog()
    {
        custAccount = fldCustAccount.value();
        return super();
    }

    public void run()
    {
        // Your business logic here
        info(strFmt("Processing customer: %1", custAccount));
    }

    public container pack()
    {
        return [custAccount];
    }

    public boolean unpack(container packedClass)
    {
        [custAccount] = packedClass;
        return true;
    }

    public static void main(Args _args)
    {
        MyBatchJob job = new MyBatchJob();
        if (job.prompt())
        {
            job.runOperationNow();
        }
    }
}

SysOperation framework

SysOperation separates concerns into a Service class, a Data Contract, and a Controller. It’s more verbose but far more testable and composable.

// 1. Data contract — defines parameters
[DataContractAttribute]
class MyServiceContract
{
    CustAccount custAccount;

    [DataMemberAttribute('CustAccount')]
    public CustAccount parmCustAccount(CustAccount _custAccount = custAccount)
    {
        custAccount = _custAccount;
        return custAccount;
    }
}

// 2. Service — the actual business logic
class MyService
{
    public void process(MyServiceContract _contract)
    {
        info(strFmt("Processing: %1", _contract.parmCustAccount()));
    }
}

Key differences

RunBaseSysOperation
TestabilityHard (dialog coupling)Easy (contract is a POCO)
ParallelismManualBuilt-in via SysOperationServiceController
Recommended forLegacy/simpleAll new development

For new development, always reach for SysOperation. Reserve RunBase for modifying existing legacy code.


Comments