During our code upgrade we have identified that the SysDeletedObjects configuration keys were still turned on. Also many DEL_-prefixed fields were being referred or used in various places. We had to come up with a way for finding objects marked for deletion.
The documentation gives you an idea of what to do with such elements.
https://docs.microsoft.com/en-us/dynamicsax-2012/appuser-itpro/delete-obsolete-application-objects
https://docs.microsoft.com/en-us/dynamicsax-2012/developer/best-practices-tables
The following job can produce a CSV file, which contains everything with the DEL_ prefix, their table property and layer information:
static void findDelObjectsinAOTTree(Args _args) { #Properties #AOT int row; xRefReferences xRefReferences; xRefPaths xrefPath; xRefNames xrefNames; str 4 strMatch = 'DEL_'; str 100 configKey; TreeNode treeNode; TreeNodeIterator treeNodeIterator; TreeNodeTraverser treeNodeTraverser; str 30 layerObject; int i; SetEnumerator setEnumerator; Set layers; UtilEntryLevel layerEnum; #File CommaTextIo commaTextIo; FileIOPermission permission; CustTable custTable; str fileName = @"D:\Temp\delobjectsinAOT.csv"; MenuFunction mf; void findNodes(TreeNode _treeNodeLoc, boolean traverse = false) { treeNode = TreeNode::findNode(_treeNodeLoc.treeNodePath()); treeNodeIterator = treeNode.AOTiterator(); if (traverse) { treeNodeTraverser = new TreeNodeTraverser(TreeNode::findNode(_treeNodeLoc.treeNodePath())); while (treeNodeTraverser.next()) { treeNode = treeNodeTraverser.currentNode(); if (treeNode && findProperty(treeNode.AOTgetProperties(), #PropertyName)) { if (subStr(treeNode.AOTgetProperty(#PropertyName), 0 , strLen(strMatch)) == strMatch) { if (treeNode && treeNode.TreeNodeType().isLayerAware()) { //layerObject = treeNode.AOTLayers().toString(); layers = treeNode.AOTLayers(); setEnumerator = layers.getEnumerator(); layerObject = ''; while (setEnumerator.moveNext()) { layerEnum = SetEnumerator.current(); layerObject += enum2str(layerEnum); } setEnumerator = null; } if (findProperty(treeNode.AOTgetProperties(), #PropertyConfigurationKey)) { commaTextIo.write(treeNode.treeNodePath(), treeNode.AOTgetProperty(#PropertyConfigurationKey), layerObject) ; layerObject = ''; } else { if (treeNode.AOTObjectNode()) { commaTextIo.write(treeNode.treeNodePath(), '', layerObject) ; layerObject = ''; } } } } } } else { while (treeNode) { if (treeNode && findProperty(treeNode.AOTgetProperties(), #PropertyName)) { if (treeNode && treeNode.TreeNodeType().isLayerAware()) { //layerObject = treeNode.AOTLayers().toString(); layers = treeNode.AOTLayers(); setEnumerator = layers.getEnumerator(); layerObject = ''; while (setEnumerator.moveNext()) { layerEnum = SetEnumerator.current(); layerObject += enum2str(layerEnum); } setEnumerator = null; } if (subStr(treeNode.AOTgetProperty(#PropertyName), 0 , strLen(strMatch)) == strMatch) { if (findProperty(treeNode.AOTgetProperties(), #PropertyConfigurationKey)) { commaTextIo.write(treeNode.treeNodePath(), treeNode.AOTgetProperty(#PropertyConfigurationKey), layerObject) ; layerObject = ''; } else { if (treeNode.AOTObjectNode()) { commaTextIo.write(treeNode.treeNodePath(), '', layerObject) ; layerObject = ''; } } } } treeNode = treeNodeIterator.next(); } } treeNode = null; treeNodeIterator = null; treeNodeTraverser = null; } if (!isRunningOnServer()) { mf = ClassFactory::makeObjectOnServer(classNum(MenuFunction)); mf.objectType(MenuItemObjectType::Job); mf.object(funcName()); mf.runOn(ClassRunMode::Server); mf.run(); return; } else { info('running code on server side'); } permission = new FileIOPermission(fileName,#io_write); permission.assert(); commaTextIo = new CommaTextIo(fileName,#io_write); commaTextIo.outFieldDelimiter('|'); treeNode = TreeNode::findNode(#AOTRootPath); treeNodeIterator = treeNode.AOTiterator(); TreeNode = treeNodeIterator.next(); findNodes(TreeNode::findNode(#TablesPath), true); findNodes(TreeNode::findNode(#ExtendedDataTypesPath)); findNodes(TreeNode::findNode(#BaseEnumsPath)); findNodes(TreeNode::findNode(#ViewsPath), true); findNodes(TreeNode::findNode(#TableMapsPath), true); findNodes(TreeNode::findNode(#FormsPath)); findNodes(TreeNode::findNode(#ClassesPath)); findNodes(TreeNode::findNode(#MenusPath)); findNodes(TreeNode::findNode(#MenuItemsDisplayPath)); findNodes(TreeNode::findNode(#MenuItemsOutputPath)); findNodes(TreeNode::findNode(#MenuItemsActionPath)); findNodes(TreeNode::findNode(#SecPrivilegesPath)); info('Export has finished'); }
The final results looks like this after executing the job for finding objects marked for deletion: