How to get a list of all the layers on which customization has been made?

In Dynamics AX 4.0 & 2009, all layer customizations are stored in AOD files. In Dynamics AX 2012, the AOD files have been replaced by SQL model data store. Sometimes, a developer may want to know what all layers a particular object has been customized on? For this, there are two possible solutions available.

  1. Querying UtilElements table

  2. Using TreeNode class


The UtilElements system table can be considered a representation of the AOD file in a table format. We can query any kind of information like, which layer an object has been customized, what has been customized, the source code for an object on a particular layer, the number of times an object has been saved, who created or updated the object etc.

The advantage of using UtilElements is that it is extremely fast.

The second approach is using the TreeNode class. The method applObjectLayerMask() returns an integer whose value is a bitwise representation of all the layers on which the object has been customized.

Let us look at this in more details.

There are a total of 16 layers including the patch layers. Now the applObjectLayerMask() method returns an integer value where each bit is representing a layer.

So if a user has customization on all of the 16 layers, the number returned by the applObjectLayerMask() method will be 65536.

The image below gives the bitwise representation of the layers and their values.


To see if customizations have been done on a particular layer, we just need to AND the value returned by applObjectLayerMask() with the bit value of that particular layer.

Suppose, you want to see what AOT properties have changed between different layer. Now, for this you will have to rely on the TreeNode class itself. The method TreeNode.getNodeInLayer() returns a copy of the object in a particular layer.

Let us see all that we have discussed here working in code.

static void checkForLayer(Args _args)
{
TreeNode treeNode,
treeNodeInLayer;

Array layerArray;
DictEnum dictEnum;
int objectLayers;

UtilElements utilElements;

int i, j;

#define.LayerCount(16)
#AOT
#Properties
;

setprefix("Checking for layer customizations using differnet approaches");

// * * * Solution 1 * * * //
// Using UtilElements to query a particular object
// We can query for modifications at deeper levels like fields, relations or methods
while select utilLevel from utilElements
group by utilLevel
where (utilElements.name == tableStr(Address) &&
utilElements.recordType == UtilElementType::Table) ||
utilElements.parentId == tableNum(Address)
{
setprefix("Using UtilElements");
info(strfmt('Address table has customizations on %1 layer', utilElements.utilLevel));
}

// * * * Solution 2 * * * //
// Using TreeNode to find a particular object node
// Using the TreeNode.applObjectLayerMask() method to see what layers the object has been
// customized on

layerArray = new Array(Types::String);
dictEnum = new DictEnum(enumNum(UtilEntryLevel));

// Store all layer names in an array
// We are using the UtilEntryLevel because the layers have changed in AX 4.0, AX 2009 and AX 2012
for (i = 0; i < dictEnum.values(); i++)
{
layerArray.value(i+1, dictEnum.value2Name(i));
}

treeNode = TreeNode::findNode(#TablesPath + '\\Address');

objectLayers = treeNode.applObjectLayerMask();

for (i = 0; i < #LayerCount; i++)
{
setprefix("Using TreeNode");
j = objectLayers;

// Do a bitwise AND on the mask to see if the bit is on or off.
j = j & power(2, i);

if (j)
{
info(strfmt("Object has been customized in %1 layer",layerArray.value(i + 1)));
}
}

// * * * Check for any property changed on a particular layer * * * //
treeNode = TreeNode::findNode(#TablesPath + '\\Address');
treeNodeInLayer = treeNode.getNodeInLayer(UtilEntryLevel::usr);

info(strfmt("Value of %1 property on usr layer is %2", #PropertyCreatedby, treeNodeInLayer.AOTgetProperty(#PropertyCreatedby)));
}

Please feel free to ask if you need help with the above code or comment if you have anything.

Hope this helps. That is all for today, do come back later for more.

Comments

Popular posts from this blog

How to add empty ranges in query

Get selected records in Dynamics AX 2012

How to refer to form controls in code without setting the AutoDeclaration property in Dynamics AX?