[X++] SysOperationFramework DataContract Query

When creating a service or batch function with the Sys Operation Framework in Dynamics AX 2012 and the need to modifiy the query via code comes in, most people tend to let the user decide and prevent query changes via code because they don't know the proper way.

Taking a look at a normal DataContract class with a query, we'll find something similar to the following:
classDeclaration

[DataContractAttribute]
class MyContract
{
    str             packedQuery;
    TransDate       transferDate;
}

parmPackedQuery

[
    DataMemberAttribute,
    AifQueryTypeAttribute('_packedQuery', queryStr(VendPurchOrderJournalListPage))
]
public str parmPackedQuery(str _packedQuery = packedQuery)
{
    packedQuery = _packedQuery;

    return packedQuery;
}

Basically the method parmPackedQuery defines the query to be used in the dialog to give the user the ability to filter by query.

Now imagine the case where you have to decide by code which query to use or you want to add ranges by code.

First, delete the definition of a specific query from your AifQueryTypeAttribute in your parmPackedQuery method:

[
    DataMemberAttribute,
    AifQueryTypeAttribute('_packedQuery', '')
]
public str parmPackedQuery(str _packedQuery = packedQuery)
{
    packedQuery = _packedQuery;

    return packedQuery;
}

Then add the following methods (explainations in comments):
getQuery

// This method unpacks the query and returns it as query object.
public Query getQuery()
{
    return 
    new Query(SysOperationHelper::base64Decode(packedQuery));
}

setQuery

// This method takes a query object, encodes it and stores the packed query.
public void setQuery(Query _query)
{
     packedQuery = SysOperationHelper::base64Encode(_query.pack());
}

initQuery

public void initQuery()
{
// Use this method to add ranges etc. for example:
    Query   newQuery;
    // init Query
    newQuery = new Query(queryStr(VendPurchOrderJournalListPage));
    // add range
    // ...
    // set Query
    this.setQuery(newQuery);
}

Now in your Controller class you can set the query.
My approach is to do it in a method called newFromArgs:

(Please be aware that some lines are splitted by a dash (-) because of the layout of my blog and they are normally one single line)
public static MyController newFromArgs(Args _args)
{
    MyController      controller;
    MyContract        contract;
    SysDictMethod     dictMethod;
    MenuFunction      callerMenuItem;
    str               contractParameterName;
controller = new MyController();
controller.initializeFromArgs(_args);
// nice way to get the "_contract" name of the parameter:
dictMethod = new SysDictMethod(UtilElementType::ClassInstanceMethod, className2Id(exportController.parmClassName()), exportController.parmMethodName());
contractParameterName = dictMethod.parameterName(1);

contract = controller.getDataContractObject(contractParameterName);
controller.parmContract(contract);

if (_args)
{
   callerMenuItem = new MenuFunction(_args.menuItemName(), _args.menuItemType());
   if (callerMenuItem)
   {
   controller.parmDialogCaption(callerMenuItem.label());
   }
}
contract.initQuery();
//Importantto call queryChanged!
controller.queryChanged(strFmt('%1.parmPackedQuery', contractParameterName), contract.getQuery());
controller.parmLoadFromSysLastValue(false);

return controller;

}