My problem is setting some dimension values read from an external source.
Given the AX 2009 statement:
ledgerJournalTrans.Dimension = ledgerTable.Dimension;
ledgerJournalTrans.Dimension[1] = "abc";
What is the equivalent way to that in AX 2012?
This will of cause assume the existence of a "Department" dimension as the first dimension.
First things first, the legacy dimensions in AX 2009 have been completely redone and replaced in AX 2012. The new LedgerDimension are a combination of the account and the old dimension values that are needed based on the account structure and advanced rule structures. To find out more about the new Dimension Framework in AX 2012 try reading the whitepaper about the new dimension framework.
Assuming that Department is the first dimension and that both dimensions are using the LedgerDimensionAccount EDT simplifies this scenario quite a bit, but the new dimension framework is very flexible so this assumption may not be correct. Even if it is, simply specifying a new value for Department may require that the structure of the combination needs to change drastically because of advanced rule structures that can be setup.
Honestly, I would only consider the code below as just a demonstration how some of the basics work, not something that should be used in production. With that said, this code should accomplish what you want, if that Dimension field on LedgerTable has be replaced with a LedgerDimension field using the LedgerDimensionAccount EDT which stores a full combination.
DimensionStorage dimensionStorage;
DimensionAttribute deparmentDimensionAttribute;
DimensionAttributeValue newDepartmentValue;
// Find the deparment dimension attribute
deparmentDimensionAttribute = DimensionAttribute::findByName("Department");
// Find the new department value we want to put in the new combination.
newDepartmentValue = DimensionAttributeValue::findByDimensionAttributeAndValue(deparmentDimensionAttribute, "abc");
// Load a DimensionStorage instance with the old combination and update the first segment with new value
dimensionStorage = DimensionStorage::findById(ledgerTable.LedgerDimension);
dimensionStorage.setSegment(1,DimensionStorageSegment::constructFromValue("abc", newDepartmentValue));
ledgerJournalTrans.LedgerDimension = dimensionStorage.save();
My case was the "default dimensions" scenario, so I had to adapt a little.
This is the method I eventually used:
On the DimensionAttribute
table add a new field name Number
then add this method:
public static DimensionAttribute findByNumber(DimensionOrdinal _number)
{
DimensionAttribute dimensionAttribute;
select firstonly dimensionAttribute where dimensionAttribute.Number == _number;
return dimensionAttribute;
}
This explicitly identifies the dimension with a corresponding number.
On the DimensionAttributeValueSetStorage
class add the method:
public void addItemNumber(DimensionOrdinal _idx, SysDim _value)
{
DimensionAttributeValue attrValue;
DimensionAttribute attr = DimensionAttribute::findByNumber(_idx);
if (!attr)
throw error(strFmt("@SYS342559", _idx));
attrValue = DimensionAttributeValue::findByDimensionAttributeAndValue(attr, _value, false, true);
this.addItemValues(attr.RecId, attrValue.RecId, attrValue.HashKey);
}
The DimensionAttributeValueSetStorage
handles "default dimensions" as described in the white paper @dlannoye mentioned.
Then the corresponding code read like this:
dimensionStorage = DimensionAttributeValueSetStorage::find(salesTable.DefaultDimension);
dimensionStorage.addItemNumber(1, "abc");
salesTable.DefaultDimension = dimensionStorage.save();
You can get 2 methods for doing this here:
http://daxldsoft.blogspot.it/2012/11/ax-2012-financial-dimension-update.html