Pages

Wednesday, June 18, 2014

[AX 2012 Upgrade] Identifying bad EDT relations using reflection and creating custom project with them.

In AX 2012, relations are no longer supported under Extended Data Types.

During an upgrade where you are re-implementing, it's common to import database schema via XPO to get your table structure with EDTs.

Sometimes EDTs that are brought over end up pointing to non-existent tables and/or and you change/rename tables, things get broken.

To uplift your old EDT relations to their corresponding tables, you can use the EDT Relation Migration Tool (http://msdn.microsoft.com/en-us/library/gg989788.aspx) located under Tools>Code Upgrade>EDT Relation Migration Tool.

My first time running this tool, it errored with "The table  does not exist."

Which was due to an EDT that was imported that had a broken table relation.

This job will loop over every CUS+ EDT, and if it has a relation, check if it's valid.  If it is not, it will create a private project of the EDTs with errors.  You can easily change it to search different layers/models/etc.  I only limited to the CUS layer for performance.

static void JobCreateProjWithBrokenEDTs(Args _args)
{
    #define.ProjName('BadEDTs')

    SysProjectFilterRunBase     projectFilter = new SysProjectFilterRunBase();
    ProjectNode                 projectNode;
    UtilElements                utilElements;

    SysModelElement             modelElement;
    SysModelElementType         modelElementType;
    SysModelElementData         modelElementData;

    SysDictType                 sysDictType;
    SysDictRelation             sysDictRelation;
    TableId                     tableId;
    SysDictTable                sysDictTable;
    SysDictField                sysDictField;
    FieldName                   fieldName;
    int                         i;

    void addBadEDT(SysModelElement _modelElement)
    {
        utilElements = null;
        utilElements.Name = _modelElement.Name;
        utilElements.ParentID = _modelElement.ParentId;
        utilElements.RecordType = _modelElement.ElementType;

        if (utilElements.RecordType == UtilElementType::SharedProject ||
            utilElements.RecordType == UtilElementType::PrivateProject ||
            utilElements.RecordType == UtilElementType::ClassInternalHeader ||
            utilElements.RecordType == UtilElementType::TableInternalHeader ||
            !projectFilter.doUtilElements(utilElements))
        {
            info(strfmt("@SYS316339", strfmt('%1 %2', utilElements.RecordType, utilElements.Name)));
        }
    }

    projectFilter.grouping(SysProjectGrouping::AOT);

    while select modelElement
        join Name from modelElementType
            where modelElementType.RecId == modelElement.ElementType    &&
                  modelElementType.RecId == UtilElementType::ExtendedType
        join modelElementData
            where modelElementData.ModelElement == modelElement.RecId   &&
                  modelElementData.Layer        >= (UtilEntryLevel::cus-1)
    {
        sysDictType = new sysDictType(modelElement.AxId);

        if (sysDictType)
        {
            sysDictRelation = sysDictType.relationObject();

            if (sysDictRelation)
            {
                tableId = sysDictRelation.table();

                sysDictTable = new SysDictTable(tableId);

                if (sysDictTable)
                {
                    // Found an EDT with a valid table, check if the field
                    // relations are good
                    for (i = 1; i <= sysDictRelation.lines(); i++)
                    {
                        fieldName = fieldid2name(tableId,sysDictRelation.lineExternTableValue(i));

                        sysDictField = new SysDictField(sysDictTable.id(),fieldname2id(sysDictTable.id(),fieldName));

                        if (!sysDictField)
                        {
                            // Field relation is bad on EDT
                            warning (strFmt("%1 found table, missing field on table %2", sysDictType.name(), sysDictTable.name()));
                            addBadEDT(modelElement);
                        }
                    }

                }
                else
                {
                    // Found an EDT with a broken table relation
                    warning(strFmt("%1 missing valid table", sysDictType.name()));
                    addBadEDT(modelElement);
                }
            }
        }
    }

    SysUpgradeProject::delete(#ProjName, ProjectSharedPrivate::ProjPrivate);
    projectNode = SysTreeNode::createProject(#ProjName);
    projectFilter.parmProjectNode(projectNode);
    projectFilter.write();

    info(strFmt("Created private project %1", #ProjName));
}

Wednesday, June 4, 2014

AX 2012 TFS Synchronizing multiple models at the same time in 1 line of code!

AX TFS version control sync'ing is designed out of the box to allow you to synchronize multiple models, but for some reason Microsoft intentionally disabled this via code.  This is my only concern...why did they intentionally disable it?

I've done some light testing with multiple models and it appears to be working fine synchronizing multiple models.  I've added this code in our development environment with the caveat among the other developers that Microsoft encourages syncing 1 model at a time in code, but syncing multiple seems to work just fine.

Change this one line in \Classes\SysVersionControlUserInterfaceMorphX\promptForFolder to:






And now you can check multiple models to sync at the same time