Sometimes there is a requirement to display data in a temporary table in a form. It is quite simple if you follow all the required steps.
To be continued...
Anton Venter's Dynamics 365 Finance and Operations blog
Sometimes there is a requirement to display data in a temporary table in a form. It is quite simple if you follow all the required steps.
To be continued...
The SysOperation framework is used for tasks or jobs (operations) that can optionally run in batch. This framework is just one of the many frameworks in F&O and can be used to add your own custom code to perform operations in F&O. Menu items can be used to launch operations in F&O and also with custom code that uses the SysOperation framework. A menu item is used to launch the operation and can be added in the Main Menu or can be added to a form. The user can click on the menu item to launch the operation. Launching the operation with a menu item is not the only way, custom operations can be called in code as well and is very common in the standard application.
Note: even though it is possible to use the SysOperation framework with just two classes, in other words without a custom controller class, I recommend using the "three class" method. This separates everything in a separate class which you can easily maintain. This three class patterns in the SysOperation framework, is identical to the well known Model View Controller (MVC) design pattern.
The three class method uses a dedicated class for threee separate roles. In simple terms:
They relate to the MVC design pattern like this:
Okay, let's go a bit deeper and let's break this down a bit.
The business logic class contains the business logic. My service classes always just does one thing. For example, update the status of data from one status to another. Over the years, I have developed the habit of ending my business logic class names with the word "service", for service class. I could have chosen something different but I started using this word never stopped. By the way, the class name can be anything you like. But for me, ending the business logic class name with service, makes it easier to identify which class contains the business logic.
The data contract class, contains class members or fields that will automatically be displayed to the user by the SysOperation framework. The data contract class is used for the user interface and the business logic. Any values entered by the user in the user interface, are saved and passed on to the business logic class. When the operation is started, the user is optionally presented with a user interface that enables the user to set some parameters prior to execution of the operation. When the user interface is displayed, the user can decide to either confirm and run the operation or cancel the operation.
The controller class that orchestrates the execution of the operation and the user input in the form of a graphical interface. The controller class itself does not contain any business logic and usually contains an entry point (static main method) that allows it to be invoked using a menu item from the user interface (form).
Let's start with a basic example of using the SysOperation framework with the "three class" method. It is an example where you can enter a name and it will show you the name you entered. You might notice that class contains a member called packedQuery and some methods related to the query. In this example just ignore the query part. Usually the query is used to select data and process the data.
[DataContractAttribute]
public class MySysOpContract
{
private Name userName;
private str packedQuery;
[DataMemberAttribute]
public Name parmUserName(Name _userName = userName)
{
userName = _userName;
return userName;
}
public Query getQuery()
{
return new Query(SysOperationHelper::base64Decode(packedQuery));
}
public void setQuery(Query _query)
{
packedQuery = SysOperationHelper::base64Encode(_query.pack());
}
[DataMemberAttribute, AifQueryTypeAttribute('_packedQuery', queryStr(CustTable))]
public str parmQuery(str _packedQuery = packedQuery)
{
packedQuery = _packedQuery;
return packedQuery;
}
}
The contract class contains the optional query and parameters for the operation. The contract class is basically a class with all the variables needed for the operation. E.g. if you have an operation to update the status of a record or records, you want the new status to be a parameter of the operation. You can set this status in the contract class in code or in the user interface and execute the operation. The business logic updates the data with the status provided in the contract class.
[DataContractAttribute] Required. A class decoration so that this class can be serialized by the framework.
private str packedQuery Optional. The packed query.
getQuery Optional. A method to get the query.
setQuery Optional. A method to set the query.
parmQuery Optional. A method to get/set the query.
public class MySysOpService
{
public void runSysOp(MySysOpContract _data)
{
info(strFmt("Hello '%1'!", _data.parmUserName()));
}
}
The service class contains the business logic for the operation. The class method must be public and contains a single argument, the contract class. The contract class contains the query and parameters for the operation. Note: The class name should not be generic but clearly indicate its function e.g. MyCustomerDiscountUpdateService.
public class MySysOpController extends SysOperationServiceController
{
public static void main(Args _args)
{
MySysOpController operation = new MySysOpController();
operation.startOperation();
}
public void new(IdentifierName _className = '', IdentifierName _methodName = '', SysOperationExecutionMode _executionMode = SysOperationExecutionMode::Asynchronous)
{
super(_className, _methodName, _executionMode);
this.parmClassName(classStr(MySysOpService));
this.parmMethodName(methodStr(MySysOpService, runSysOp));
this.parmDialogCaption("Hello user");
}
}
The controller class is used to launch the operation and to connect the operation with our method in our service class.
public static void main - The entry point of the controller class, this method is called by F&O when the operation is launched. The method instantiates an instance of our operation and calls a single method startOperation. The controller class contains a main method and is called when a user clicks on the operations menu item. Note: the main method is usually not called from code.
public void new - The new method is called when the controller class is instantiated and sets the service class and class method name. Note: this is how F&O knows that our method must be called in the operation. The dialog caption is set in the new method.
x. Create a service class. Using the query and parameters to update.
public void runQuery(MySysOpContract _data)
{
//add your custom code here
Query query;
QueryRun queryRun;
CustTable custTable;
query = _data.getQuery();
queryRun = new QueryRun(query);
while (queryRun.next())
{
custTable = queryRun.get(tableNum(CustTable));
info(custTable.AccountNum);
}
}
Post script
I use the SysOperation framework extensively for all the custom code I write. I break down the business logic into smaller pieces and create a specific class for each operation using the SysOperation framework. This provides flexibilty and maximizes re-use of the code. I have seen the benefits of this approach many times.
Examples:
To be continued...
Sometimes you just need a fast way to get data from F&O for real time processing of data. We were debating the architecture and exporting data to a data warehouse was not meeting one of the requirements which was speed. They need the data to be up to date in real time. My solution to this was to use set based operations to fill a temporary table and to expose the data in the temporary table in the service. I am very happy with the performance of this service and definitely recommend using this pattern to everyone out there.
Let's start.
Create a temporary table with the fields that you will need to expose. Set the Table Type property to TempDB.
The service will expose the data as an endpoint.
To be continued...