Recently we have decided to merge two AX models sitting in different layers with overlapping objects as part of our code cleanup exercise, thus the requirement came to export AX model from code in a specific AOT layer only.

The following 3 object types has to be exported:

  • X++ metadata and code
  • Project definitions
  • Label files

By providing the name of the model and the export path for the XPOs and labels, the following job can be executed to export AX model from code if you log on to the layer where the model is sitting:

static void WIK_ExportLayer(Args _args)
{
    #define.ModelToExport1("ISV Model")
    #define.ModelToExport2("USR Model")
    #define.ExportDestination(@"C:\Temp\")
    #AOTExport
    boolean     currentLayerOnly = true;

    void exportModel(ModelName _modelName)
    {
        ProjectNode             project;
        SysModelCreateProject   createProject   = SysModelCreateProject::construct();
        ProjectName             projectName     = strReplace(_modelName, ' ', '_') + '_All';
        SysModel                model;
        SysModelManifest        modelManifest;
        SysModelElement         modelElement;
        SysModelElementData     modelElementData;
        SysLabelFileExport      label           = SysLabelFileExport::construct();

        select firstOnly Model, RecId from modelManifest
            where modelManifest.Name == _modelName
            join Layer from model
                where modelManifest.Model   == model.RecId
                    && model.Layer          == currentAOLayer();

        createProject.parmModelId(modelManifest.RecId);
        createProject.parmProjectName(projectName);

        if (createProject.parmModelId())
        {
            // Export model metadata and source
            createProject.run();
            project = SysTreeNode::getPrivateProject().AOTfindChild(projectName);
            project.treeNodeExport(#ExportDestination + projectName + '.xpo', currentLayerOnly ? #export | #expLayer : #export);

            // Export label files and languages
            while select modelElement
                where modelElement.ElementType  == UtilElementType::LabelFileLanguage
                exists join modelElementData
                    where modelElementData.ModelId  == modelManifest.Model
                        && modelElement.RecId       == modelElementData.ModelElement
            {
                label.parmTreenode(TreeNode::findNode(SysTreeNode::modelElement2Path(modelElement)));
                label.parmPath(#ExportDestination);
                label.run();
            }

            // Export project definitions
            while select modelElement
                where modelElement.ElementType  == UtilElementType::SharedProject
                exists join modelElementData
                    where modelElementData.ModelId  == modelManifest.Model
                        && modelElement.RecId       == modelElementData.ModelElement
            {
                project = TreeNode::findNode(SysTreeNode::modelElement2Path(modelElement));
                if (!WinAPI::folderExists(#ExportDestination + 'Projects'))
                {
                    WinAPI::createDirectory(#ExportDestination + 'Projects');
                }
                project.treeNodeExport(#ExportDestination + @'Projects\' + enum2str(currentAOLayer()) + modelElement.Name + '.xpo', currentLayerOnly ? #export | #expProjectOnly | #expLayer : #export | #expProjectOnly);
            }
        }
        else
        {
            error(strFmt('Layer %1 does not have model %2', strUpr(enum2str(currentAOLayer())), _modelName));
        }
    }

    exportModel(#ModelToExport1);
    exportModel(#ModelToExport2);
}

The results will contain the three components we have identified – 1 XPO for the model, ALD files per label and language, and all shared project definitions in a subfolder.