Replace a Financial Dimension in Default Dimensions–Condensed [AX 2012]

In my previous post on Replacing default dimensions, I had provided a job to replace one financial dimension within a default dimension. The job was pretty big and I always thought that Microsoft should have provided some way to do these operations easily. Luckily I found a class that has helped me to condense that job and make it pretty small. I am sharing that job here:

The dimensions for Customer record looks like this before running the job:


Here is the job to change the values. We will change the values for Business Unit, Department and Worker all with this simple job:

static void replaceDefaultDimensionsCondense(Args _args)



     * In this job, we will replace the Business Unit Value from BU-001 to BU-002

     * and fill in the values for Department as Dep-001 and Worker as 114


    CustTable                       custTable = CustTable::find(‘CUS-00004’); //Customer Record containing Financial Dimension

    Struct                          struct = new Struct(); //Structure to hold the dimension values to replace

    container                       defDimensionCon; //Container to prepare the required values and dimension attribute combination

    DimensionDefault                dimensionDefault; //Get the replaced dimension recid

    DimensionAttributeSetItem       dimAttrSetItem; //Table to get active dimensions for the legal entity

    DimensionAttribute              dimAttribute; //Table to get the Financial dimensions

    int i; //For looping


    //Loop for required dimensions

    while select Name, BackingEntityType from dimAttribute

        where dimAttribute.BackingEntityType == tableNum(DimAttributeOMBusinessUnit) ||

              dimAttribute.BackingEntityType == tableNum(DimAttributeOMDepartment) ||

              dimAttribute.BackingEntityType == tableNum(DimAttributeHcmWorker) &&

              dimAttribute.Type              != DimensionAttributeType::DynamicAccount

              join dimAttrSetItem

                where dimAttrSetItem.DimensionAttribute == dimAttribute.RecId &&

                      dimAttrSetItem.DimensionAttributeSet == DimensionCache::getDimensionAttributeSetForLedger()


        //Add the Dimension name and display value to struct

        if (dimAttribute.BackingEntityType == tableNum(DimAttributeOMBusinessUnit))


            struct.add(dimAttribute.Name, ‘BU-002’);


        else if (dimAttribute.BackingEntityType == tableNum(DimAttributeOMDepartment))


            struct.add(dimAttribute.Name, ‘DEP-002’);


        else if (dimAttribute.BackingEntityType == tableNum(DimAttributeHcmWorker))


            struct.add(dimAttribute.Name, ‘114’);




    //Prepare the container

    defDimensionCon += struct.fields();


    for (i = 1; i <= struct.fields(); i++)


        defDimensionCon += struct.fieldName(i);

        defDimensionCon += struct.valueIndex(i);



    //if there are fields in struct

    if (struct.fields())


        //Get the DimensionAttributeValueSet table’s Record ID

        dimensionDefault = AxdDimensionUtil::getDimensionAttributeValueSetId(defDimensionCon);


        //Update to Customer



        if (custTable.DefaultDimension)


            custTable.DefaultDimension = DimensionDefaultingService::serviceMergeDefaultDimensions(dimensionDefault, custTable.DefaultDimension);




            custTable.DefaultDimension = dimensionDefault;







Dimensions after running the job:


Pretty Neat!

The class AxdDimensionUtil is pretty handy to do all these stuff.

Replace a Financial Dimension in Default Dimensions [AX 2012]

In my earlier post, I had explained how we can set financial dimensions. In this post, I will provide a job by which we can replace one attribute value in a combination of financial dimensions.

The class that we can use is the DimensionDefaultingService and method to use is “serviceReplaceAttributeValue”.

For this purpose, we will use the following combination taken from a customer record.


In this financial dimensions, we will replace value if worker from “114” to “51011”.

The job below will be helpful for you to see how this can be achieved.

static void replaceDefaultDimensions(Args _args)


    CustTable                       custTable = CustTable::find(‘CUS-00004’); //Customer Record containing Financial Dimension

    DimensionSHA1Hash               hash; //To store the calculated hash for DimensionAttributeValueSet

    DimensionAttribute              dimAttr; // Contains the financial dimensions records

    DimAttributeHcmWorker           dimAttrWorker; //Backing entity view for Employee type dimension

    DimensionDefault                defaultDimension;

    DimensionEnumeration            dimensionSetId; //Record id for table that contains active dimensions for current ledger

    DimensionAttributeValue         dimAttrValue; // Contains used financial dimension values

    DimensionAttributeValueSet      dimAttrValueSet; //Contains default dimension records

    DimensionAttributeValueSetItem  dimAttrValueSetItem; //Contains individual records for default dimensions

    DimensionAttributeSetItem       dimAttrSetItem; // Contains the number of dimensions active for a account structure ledger


    HashKey valueKeyHashArray[]; //To store the has key of dimension in question

    Map     dimAttrIdx, dimAttrRecId; //to store the dimension index and backing entity type

    int     dimAttrCount, i;

    int     emplBackEntityType; //Stores the backing entity type for Employee type dimension


    //The employee backing entity will be the view DimAttributeHcmWorker

    emplBackEntityType = tableNum(DimAttributeHcmWorker);


    //Initialize the map to store the backing entity types

    dimAttrIdx = new Map(Types::Integer, Types::Integer);

    dimAttrRecId = new Map(Types::Integer, Types::Int64);

    //Get the record Id (dimension set id) for current ledger to find active dimensions

    dimensionSetId = DimensionCache::getDimensionAttributeSetForLedger();


    //Find all the active dimensions for current ledger except main account and store there

    //backing entity type in the map

    while select * from dimAttr

            order by Name

            where dimAttr.Type != DimensionAttributeType::MainAccount

        join RecId from dimAttrSetItem

            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&

                dimAttrSetItem.DimensionAttributeSet == dimensionSetId



        dimAttrIdx.insert(dimAttr.BackingEntityType, dimAttrCount);

        dimAttrRecId.insert(dimAttr.BackingEntityType, dimAttr.RecId);



    //Get the backing entity type for the dimension value to process

    select firstOnly dimAttrWorker

        where dimAttrWorker.Value == "51011";


    //initialize hash key array to null

    for (i = 1; i<= dimAttrCount; i++)

        valueKeyHashArray[i] = emptyGuid();


    //Find the Dimension attribute record for the dimension to work on, in our case it is HcmWorker


    dimAttr = DimensionAttribute::find(dimAttrRecId.lookup(emplBackEntityType));


    //Get the backing entity type for the dimension value to process

    select firstOnly dimAttrWorker

        where dimAttrWorker.Value == "51011";


    //Find the required Dimension Attribute Value record

    //Create if necessary

    dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndEntityInst(dimAttr.RecId, dimAttrWorker.RecId, false, true);


    //Replace the required combination hash keys and other value arrays

    i = dimAttrIdx.lookup(emplBackEntityType);

    valueKeyHashArray[i]    = dimAttrValue.HashKey;


    //Calculate the hash for the current values

    hash = DimensionAttributeValueSetStorage::getHashFromArray(valueKeyHashArray, dimAttrCount);


    //Null hash indicates no values exist, which may occur if the user entered an invalid value for one dimension attribute

    if (hash == conNull())


        throw error("Wrong value for Employee Dimension");



    // Search for existing value set

    dimAttrValueSet = DimensionAttributeValueSet::findByHash(hash);


    // This value set does not exist, so it must be persisted

    if (!dimAttrValueSet)




        // Insert the value set with appropriate hash

        dimAttrValueSet.Hash = hash;



        // Insert only specified set items use this


        dimAttrValueSetItem.DimensionAttributeValueSet = dimAttrValueSet.RecId;

        dimAttrValueSetItem.DimensionAttributeValue = dimAttrValue.RecId;

        dimAttrValueSetItem.DisplayValue = dimAttrWorker.Value;






    defaultDimension = DimensionDefaultingService::serviceReplaceAttributeValue(custTable.DefaultDimension, dimAttrValueSet.RecId, dimAttr.RecId);




    custTable.DefaultDimension = defaultDimension;





This is the output after running this job.