Skip to main content

Throw behaviour in X++

· 3 min read
Kome Hoang
Maintainer of Automaly

References

How to

Prerequisite

For the purpose of testing, I had this data set of CustGroup. This can also be found on Legal Entity USRT of demo data comes with a new environment of Dynamics 365 Finance.

Customer groupDescription
10Wholesale customers
20Major customers
30Retail customers
40Internet customers
50Employees
80Wholesale customers
90Wholesale customers

I added two new buttons on CustGroup form:

  • Bulk update Desc: This button will loop through each and all records in the above table and update the Description to Description + + Updated except one containing "Employee". They will become like below.
Customer groupDescription
10Wholesale customers + Updated
20Major customers + Updated
30Retail customers + Updated
40Internet customers + Updated
50Employees
80Wholesale customers + Updated
90Wholesale customers + Updated
  • Reverse Bulk update Desc: This button will update all Description back to its original by removing the word + Updated.

Let's do it

When we don't use throw

In the extension class named CustGroup_ButtonHandlers, I put these codes which will handle the event of clicking those two buttons.

tip

This type of FormControlEventHandler will only be needed when you are extending a standard form. For a totally custom form, you can add a Clicked() method method for any buttons on the form.

internal final class CustGroup_ButtonHandlers
{
[FormControlEventHandler(formControlStr(CustGroup, BulkUpdateDesc), FormControlEventType::Clicked)]
public static void BulkUpdateDesc_OnClicked(FormControl sender, FormControlEventArgs e)
{
FormDataSource custGroupDS = sender.formRun().dataSource(formDataSourceStr(CustGroup, CustGroup));

ttsbegin;

for(
CustGroup custGroup =
custGroupDS.getFirst() ?
custGroupDS.getFirst() :
custGroupDS.cursor()
; custGroup
; custGroup = custGroupDS.getNext()
)
{
if(strContains(custGroup.Name, "Employees"))
{
// Show an error here but do not stop the loop
error("This group's name contains \"Employees\". Operation skipped but continue until the end of loop.");

// Continue the loop by (1) skipping below code and (2) getting the next record from the DS
continue;
}

custGroup.Name = custGroup.Name + " + Updated";
custGroup.doUpdate();
}

ttscommit;

custGroupDS.research(true);
}

[FormControlEventHandler(formControlStr(CustGroup, BulkRevUpdateDesc), FormControlEventType::Clicked)]
public static void BulkRevUpdateDesc_OnClicked(FormControl sender, FormControlEventArgs e)
{
FormDataSource custGroupDS = sender.formRun().dataSource(formDataSourceStr(CustGroup, CustGroup));

ttsbegin;

for(
CustGroup custGroup =
custGroupDS.getFirst() ?
custGroupDS.getFirst() :
custGroupDS.cursor()
; custGroup
; custGroup = custGroupDS.getNext()
)
{
custGroup.Name = strReplace(custGroup.Name, " + Updated", "");
custGroup.doUpdate();
}

ttscommit;

custGroupDS.research(true);
}
}

Notice the part

if(strContains(custGroup.Name, "Employees"))
{
// Show an error here but do not stop the loop
error("This group's name contains \"Employees\". Operation skipped but continue until the end of loop.");

// Continue the loop by (1) skipping below code and (2) getting the next record from the DS
continue;
}

This part will do the job of updating the Description of the CustGroup record. Yet, I am calling error to display a message (which is speicifed as an "error") to users.

Now, let's click the Bulk update Desc button. You will see the error message and the updated description. We can tell that the loop was not stopped.

alt text

When we use throw

Let's change the part mentioned above to this one. Notice that we now will use throw before error.

if(strContains(custGroup.Name, "Employees"))
{
// Show an error here and break the loop
throw error("This group's name contains \"Employees\". Operation broken.");

// Below code line is actually never called because the throw will stop the code execution immediately
continue;
}

Clicking Bulk update Desc will result in this.

alt text

Yet, upon refreshing the form, we will see that no transaction within the same tts level was actually committed.

alt text

Now if we bring the tts inside the loop.

{
if(strContains(custGroup.Name, "Employees"))
{
// Show an error here and break the loop
throw error("This group's name contains \"Employees\". Operation broken.");

// Below code line is actually never called because the throw will stop the code execution immediately
continue;
}

ttsbegin;

custGroup.Name = custGroup.Name + " + Updated";
custGroup.doUpdate();

ttscommit;
}

Upop refreshing the form, we will see what transaction were commited and what part of the loop was broken.

alt text

So, that's how throw works in X++.