I have used the MetadataSupport library in X++ to help get metadata information for tables, menu items, and data entities in the past. I have also used it for enums but recently found an issue when dealing with enum extensions.
I initially wrote the logic to get enum metadata information like this:
Which seems to work just fine, until you find an enum that contains a base enum extension, for example LedgerJournalType:
We can see in this case the both ‘Daily’ and ‘RevenueRecognition’ share a value of 0, which can’t happen so what is going on?
Deterministic vs Nondeterministic Enum Values
In the AX 2012 world, we used deterministic enum values where the enum value was set at design time. In D365FO, we now have to extend enums if we want to modify them so how does D365FO handle this? They use nondeterministic values to allow for extending enums which means that the enum value is actually set at runtime (or technically when a database sync is executed). These values are then stored in the database in the
tables.We can see if a enum is being used in a nondeterministic fashion by looking at the UseEnumValue property on the enum itself. For example, the LedgerJournalType enum is set to be nondeterministic because it has UseEnumValue equal to No.
If we go the the EnumValueTable and look up what the actual enum values are we can see that we actually do not have duplicate enum values but instead Revenue Recognition is actually using the value of 5 instead of 0.
So it appears the MetadataSupport library does not look at the value of the enum extensions as they are generated at runtime instead of design time and it defaults these values to be 0 instead of their actual value.
How Do We Get Nondeterministic Enum Values Programmatically?
So if the MetadataSupport library isn’t giving the correct enum values, how can we get them programmatically? We can utilize the SysDictEnum object like in the example below:
This class correctly gathers the enum information regardless if its a deterministic or nondeterministic enum.
Conclusion
So what can we take away from this?
The first thing is that you should NEVER compare enums to an integer value using something like equals or less than/greater than can lead to incorrect logic being applied as some enums will not have the same values across environments.
If at all possible be sure that all comparisons are against the enum itself:
LedgerJournalType value = LedgerJournalType.Daily Use: if(value == LedgerJournalType.Daily) Do not use: if(value == 0)
But for ENUMS that do not have integer values in sequence, the index2LabelId() method of SysDictEnum class gives incorrect label ID when trying to fetch label ID of a particular enum value.
Try extracting the label ID of “PurchaseOrder” (13) enum value in “ProjOrigin” ENUM using index2LabelId(). You will get label ID of enum value “ProductionFinished” because in sequential counting starting from 0, “ProductionFinished” falls at 13.
How to handle such cases?
Sameer,
I’m not sure what your issue is, you are correct that for a number of enums that the values are not in sequential order but the code I provided performs the following actions:
– Gets all enum names from the MetadataSupport library
– Iterates through the names and creates a SysDictEnum object
– Iterates through the values on each enum and gets the value, label, valuename using the index2Symbol, index2Label, and index2Value methods, these methods take in the integer index position of the value on the enum they do not correspond to the enum value
Using the code provided I was able to generate the following data:
Which matches the enum reference from MSFT: https://docs.microsoft.com/en-us/previous-versions/dynamics/ax-2012/reference/gg883386(v=ax.60)