miércoles, 29 de enero de 2014

Cube measurement data, or lack there-of

Sometimes when migrating hand-crafted cubes from the development environment to production you get that sinking feeling when no transactions totals appear in the SQL Management Cube Browser.  The culprit in my experience is one of four reasons:
  • No data!  This is not actually a problem, except for live-testing. Sometimes rollouts start by using the sales and ledger module so no one has yet started inputting purchase orders into the production system. Be aware of the issue.
  • RecId differences, usually on the financial dimension sets.
    I really must write another blog post on this, but using AX to publish your cubes is preferred.
  • Virtual company/Table collection issues. As a developer be aware if virtual companies exist and how they are configured with regards to companies and table collections.
    GLOB : US : CON (Contoso DataAreaId)
    Things get worse if there are differences between your development environment and production.  Manually attempting to perform a join on this example in MSDN is going to be difficult so use AOS generated views to do this for you.
  • Eumeration label issues/SRSAnalysisEnums.  THIS issue stung me today, and has done so in the past.  Basically the cubes rely on a per installation generated table called SRSAnalysisEnums to populate the dimension attributes.  There is a great post detailing this for us, the job below will populate this table.  Remember, it may not be populated in some environments.  ALSO remember that if the enumeration does not exist in an AOS perspective, it won't get generated.  Add the table to a new perspective if you have not already do so, and relaunch the generation process. It will take a few minutes.
///If the enum doesn't exist in a Perspective, it won't get added...
///Only 'en-us' values?  See table 'BIUdmTranslations' and check those that require BI labels generated for them.
static void ZZZ_PopulateSRSAnalysisEnums(Args _args)
{;
    BIGenerator::populateSRSAnalysisEnums();
}

If like me you are in a hurry for ONE enumeration that's missing, try this job that inserts or updates the BankAccountHoldStatus value with the enumeration name that you require.
///Only 'en-us' values?  See table 'BIUdmTranslations' and check those that require BI labels generated for them.
static void ZZZ_PopulateSRSAnalysisEnums(Args _args)
{
    //;
    //BIGenerator::populateSRSAnalysisEnums();
    
    // ...Or, populate one concrete enum labels entity
    // ----------------------------------------------------------
    str enumName = 'BankAccountHoldStatus';
    // ----------------------------------------------------------
    
    // Macros and defines
    #AOT
    #Properties
    #SRSModel
    #BIFramework

    SRSAnalysisEnums analysisEnums;

    Set dictEnumSet = new Set(Types::Class);
    Set languageIdSet = new Set(Types::String);

    SetEnumerator dictEnumEnumerator;
    SetEnumerator languageIdEnumerator;

    TreeNode enumNodeRoot = TreeNode::findNode(#BaseEnumsPath);
    TreeNode enumNode;
    TreeNode enumItemNode;

    DictEnum dictEnum;

    int valueIndex;
    str labelId;
    str label;

    SRSEnumName enumItemName;
    SRSEnumValue enumItemValue;

    LanguageId languageId;

    void populateLanguageIdSet()
    {
        BIUdmTranslations translations;
        ;

        BIUdmTranslations::initialize();

        while select LanguageId, Generate from translations where translations.Generate == 1
        {
            languageIdSet.add(translations.LanguageId);
        }

        // add the default language if nothing is currently selected
        if (languageIdSet.elements() == 0)
        {
            languageIdSet.add(@"en-us");
        }
    }

    void addEnumToDictEnumSet(str _enumName)
    {
        DictEnum enum = new DictEnum(enumName2Id(_enumName));
        
        if (enum && !dictEnumSet.in(enum))
        {
            dictEnumSet.add(enum);
        }
    }

    str getLabel(LanguageId langId, str lId, str defaultName)
    {
        str value = #emptyString;
        ;

        if (lId)
        {
            value = SysLabel::labelId2String2(lId, langId);
        }

        if (value == #emptyString)
            value = defaultName;

        if (strLen(value) > #smMaxLengthEnumItemLabel)
        {
            value = subStr(value, 1, #smMaxLengthEnumItemLabel);
        }

        return value;
    }
    
    ;

    populateLanguageIdSet();
        
    addEnumToDictEnumSet(enumName);
    
    // Populate the SRSAnalysisEnums table
    dictEnumEnumerator = dictEnumSet.getEnumerator();

    ttsbegin;

    while (dictEnumEnumerator.moveNext())
    {
        dictEnum = dictEnumEnumerator.current();

        if (dictEnum == null)
        {
            continue;
        }

        enumNode = enumNodeRoot.AOTfindChild(dictEnum.name());

        for (valueIndex = 0 ; valueIndex < dictEnum.values(); valueIndex++)
        {
            labelId = #emptyString;

            enumItemName = dictEnum.index2Symbol(valueIndex);
            enumItemValue = dictEnum.index2Value(valueIndex);

            if (enumNode)
            {
                enumItemNode = enumNode.AOTfindChild(enumItemName);

                if (enumItemNode)
                {
                    labelId = enumItemNode.AOTgetProperty(#PropertyLabel);
                }
            }

            languageIdEnumerator = languageIdSet.getEnumerator();

            while (languageIdEnumerator.moveNext())
            {
                languageId = languageIdEnumerator.current();

                label = getLabel(languageId, labelId, enumItemName);

                select firstfast forupdate EnumName, LanguageId, EnumItemName, EnumItemValue, EnumItemLabel
                    from analysisEnums where analysisEnums.LanguageId == languageId && analysisEnums.EnumName == dictEnum.name() && analysisEnums.EnumItemValue == enumItemValue;

                if (analysisEnums)
                {
                    if (analysisEnums.EnumItemName != enumItemName || analysisEnums.EnumItemLabel != label)
                    {
                        analysisEnums.EnumItemName  = enumItemName;
                        analysisEnums.EnumItemLabel = label;
                        analysisEnums.update();
                    }
                }
                else
                {
                    analysisEnums.EnumName      = dictEnum.name();
                    analysisEnums.LanguageId    = languageId;
                    analysisEnums.EnumItemName  = enumItemName;
                    analysisEnums.EnumItemValue = enumItemValue;
                    analysisEnums.EnumItemLabel = label;

                    analysisEnums.insert();
                }
            }
        }
    }

    ttscommit;
}