Defaulting logic in tables (How does it work?)
Views (315)
Hello AX World,
Data entities and tables have defaulting logic that can be defined in the following methods:
While the main purpose is data entity, it is important to understand how it works on tables because defaultField is called within modifiedField.
In this blog post I will try to explain how it works.
Method defaultField is used for setting default values on fields. It is very similar to modifiedField except it is not called for every field by default.
It goes with two other methods, getDefaultingDependencies and getExtension. Without these methods, it won't get executed.
Default values are only set for the fields that have dependencies, which are defined in the method getDefaultingDependencies. It has a "predefined" structure and one field can have multiple dependencies.
The structure is a container with containers for every field that needs defaulting and a container inside every of those containers for dependencies. Multiple dependencies are separate elements (field ids) in a dependency container. If you duplicate fields that needs defaulting, only the first one is picked up.
Tables' defaulting logic is handled in implementations of TableExtension base class. When modifiedField calls Table.defaultField it actually calls TableExtension.defaultField. TableExtension is a kernel class and (probably) contains no code, therefore you should use one of the existing implementations or write your own. The implementation class must be instantiated in the getExtesion method of the table.
Let's say we have Quantity, Price and Total price fields on a table. Using defaulting logic we can define that Total price depends on Quantity and Price fields and as soon as they are modified, recalculate the value for Total price field.
So the code would look something like this:
And whenever we modify Qty or Price the Total gets updated automatically. Total is updated every time the dependent field is modified.
Don't worry, the system will not break :). Defaulting logic collect dependencies using Breadth First Search (BFS) to traverse dependency graph.
Be aware and take care!
Data entities and tables have defaulting logic that can be defined in the following methods:
- defaultRow
- defaultField
- getDefaultingDependencies
- getExtension
While the main purpose is data entity, it is important to understand how it works on tables because defaultField is called within modifiedField.
In this blog post I will try to explain how it works.
Defaulting fields, dependencies and logic
Method defaultField is used for setting default values on fields. It is very similar to modifiedField except it is not called for every field by default.
It goes with two other methods, getDefaultingDependencies and getExtension. Without these methods, it won't get executed.
Default values are only set for the fields that have dependencies, which are defined in the method getDefaultingDependencies. It has a "predefined" structure and one field can have multiple dependencies.
The structure is a container with containers for every field that needs defaulting and a container inside every of those containers for dependencies. Multiple dependencies are separate elements (field ids) in a dependency container. If you duplicate fields that needs defaulting, only the first one is picked up.
Tables' defaulting logic is handled in implementations of TableExtension base class. When modifiedField calls Table.defaultField it actually calls TableExtension.defaultField. TableExtension is a kernel class and (probably) contains no code, therefore you should use one of the existing implementations or write your own. The implementation class must be instantiated in the getExtesion method of the table.
The most common implementation is SysTableExtension. There are a couple other implementations that extend it. It is SysDefaultingProcessor and SalesPurchModifiedTableExtension.
If you have a look at SysTableExtension you can find out that first it collects field dependencies from the table method getDefaultingDependencies and later calls defaultField for every field that has a dependency.
Though there is one example (Table TrvExpTable) that is probably not working, where the field added to getDefaultingDependencies without any dependent fields specified. Method defaultField is expected to set new ID.
At first, it might look similar to initValue but it's different as it only works for fields with dependencies. Defaulting logic does not set a default value if the dependent field has not been modified. So defaulting logic on a table is a way to define dependencies and dependent logic between fields.
Have a look at the example bellow:
If you have a look at SysTableExtension you can find out that first it collects field dependencies from the table method getDefaultingDependencies and later calls defaultField for every field that has a dependency.
Though there is one example (Table TrvExpTable) that is probably not working, where the field added to getDefaultingDependencies without any dependent fields specified. Method defaultField is expected to set new ID.
How does it work?
At first, it might look similar to initValue but it's different as it only works for fields with dependencies. Defaulting logic does not set a default value if the dependent field has not been modified. So defaulting logic on a table is a way to define dependencies and dependent logic between fields.
Have a look at the example bellow:
Let's say we have Quantity, Price and Total price fields on a table. Using defaulting logic we can define that Total price depends on Quantity and Price fields and as soon as they are modified, recalculate the value for Total price field.
So the code would look something like this:
public class TestDefaultingFields extends common
{
public container getDefaultingDependencies()
{
container ret = [
[fieldNum(TestDefaultingFields, Total),
[fieldNum(TestDefaultingFields, Qty),
fieldNum(TestDefaultingFields, Price)]]
];
return ret;
}
public void defaultField(FieldId _fieldId)
{
super(_fieldId);
switch (_fieldId)
{
case fieldNum(TestDefaultingFields, Total):
this.Total = this.Qty * this.Price;
break;
}
}
public TableExtension getExtension()
{
TableExtension ret;
ret = SysTableExtension::construct();
return ret;
}
}
And whenever we modify Qty or Price the Total gets updated automatically. Total is updated every time the dependent field is modified.
Cyclic dependencies
You can also define cyclic dependencies where one field can be dependent on the other and vice versa at the same time.Have a look at CAMDataDimensionClassificationHierarchyNodeDimensionMemberRange table.
Don't worry, the system will not break :). Defaulting logic collect dependencies using Breadth First Search (BFS) to traverse dependency graph.
This was originally posted here.
*This post is locked for comments