Throw behaviour in X++
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 group | Description |
---|---|
10 | Wholesale customers |
20 | Major customers |
30 | Retail customers |
40 | Internet customers |
50 | Employees |
80 | Wholesale customers |
90 | Wholesale 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 group | Description |
---|---|
10 | Wholesale customers + Updated |
20 | Major customers + Updated |
30 | Retail customers + Updated |
40 | Internet customers + Updated |
50 | Employees |
80 | Wholesale customers + Updated |
90 | Wholesale 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.
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.
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.
Yet, upon refreshing the form, we will see that no transaction within the same tts
level was actually committed.
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.
So, that's how throw
works in X++.