For example, if you would activate a CustomerSegment dimension, the system would create a new CustomerSegment and CustomerSegmentValue columns in backing SQL table (these fields will not be visible AOT in Visual Studio) for both DimensionAttributeValueSet and DimensionAttributeValueCombination tables.
CUSTOMERSEGMENT | CUSTOMERSEGMENTVALUE |
5637144684 | 100 |
5637144684 | 100 |
5637144680 | 4000 |
Example 1: CustomerSegment and CustomerSegmentValue dimension
In this example, CustomerSegment field is the Record of the dimension’s backing entity (in this case CustTable) and CustomerSegmentValue is CustomerSegment display value.
To select a specific dimension value directly from DimensionAttributeValueCombination (or DimensionAttributeValueSet) table you will need to specify its fieldID instead of its name. For that purpose, you can use the DimensionAttributeValueCombination/getDimensionValueFieldId method.
To see how dimension-based select statements can be shortened in Dynamics 365 let’s look at an example which selects projects that have a specific BusinessUnit dimension display value:
static void CF1_GetProjectsWithCustomerSegment(Args _args) { #define.BUSINESSUNIT('BusinessUnit') ProjTable projTable; DimensionAttribute da; DimensionAttributeValue dav; DimensionAttributeValueSet davs; DimensionAttributeValueSetItem davsi; while select ProjId from projTable exists join davs where davs.RecId == projTable.DefaultDimension exists join davsi where davsi.DimensionAttributeValueSet == davs.RecId && davsi.DisplayValue == '001' exists join dav where dav.RecId == davsi.DimensionAttributeValue exists join da where da.RecId == dav.DimensionAttribute && da.Name == #CUSTOMERSEGMENT { info(projTable.ProjId); } }
Example 2: Financial dimension-based select statements in Dynamics AX 2012
class CF1_GetProjectsWithBusinessUnit { public static void main(Args _args) { Const Name BUSINESSUNIT = 'BusinessUnit'; FieldId businessUnitId; ProjTable projTable; DimensionAttributeValueSet davs; businessUnitId = DimensionAttributeValueCombination::getDimensionValueFieldId(BUSINESSUNIT); while select ProjId from projTable exists join davs where davs.RecId == projTable.DefaultDimension && davs.(businessUnitId) == '20' { info(projTable.ProjId); } } }
Example 3: Financial dimension-based select statements in Dynamics 365
As you can see, select statements are now much shorter, which in turn increases solution performance. The same applies to queries in Dynamics 365.
class CF1_GetProjectsWithBusinessUnit { public static void main(Args _args) { Const Name BUSINESSUNIT = 'BusinessUnit'; FieldId businessUnitId; ProjTable projTable; businessUnitId = DimensionAttributeValueCombination::getDimensionValueFieldId(BUSINESSUNIT); Query q; QueryRun qr; QueryBuildDataSource qbdProjTable, qbdDimensionAttributeValueSet; q = new Query(); qbdProjTable = q.addDataSource(tableNum(ProjTable)); qbdDimensionAttributeValueSet = qbdProjTable.addDataSource(tableNum(DimensionAttributeValueSet)); qbdDimensionAttributeValueSet.relations(true); SysQuery::findOrCreateRange(qbdDimensionAttributeValueSet, businessUnitId).value('20'); qr = new QueryRun(q); while (qr.Next()) { projTable = qr.get(tableNum(ProjTable)); } } }
Example 4: Financial dimension-based queries in Dynamics 365
Changes to DimensionStorage class in Dynamics 365
In Dynamics 365, quite a few methods from DimensionStorage class (which is commonly used in development projects) were moved to other classes. Here is a list of those methods:
AX 2012 DimensionStorage method | Dynamics 365 DimensionStorage method |
getMainAccountIdFromLedgerDimension | LedgerDimensionFacade/ getMainAccountRecIdFromLedgerDimension |
getMainAccountFromLedgerDimension | LedgerDimensionFacade/getMainAccountFromLedgerDimension |
getDefaultAccount | LedgerDefaultAccountHelper/getDefaultAccountFromMainAccountRecId |
getDefaultAccountForMainAccountNum | LedgerDefaultAccountHelper/getDefaultAccountFromMainAccountId |
accountNum2LedgerDimension And getDynamicAccount | LedgerDynamicAccountHelper/getDynamicAccountFromAccountNumber |
ledgerDimension2AccountNum | LedgerDynamicAccountHelper/ getAccountNumberFromDynamicAccount |
getDefaultDimensionFromLedgerDimension | LedgerDimensionFacade/getDefaultDimensionFromLedgerDimension |
There may be cases when you need to retrieve a ledger or default dimensions from display values. Doing that has changed a bit in Dynamics 365 and I will give you a few solutions options.
To get the ledger dimension from display values you will need to set each segment that has value using DimensionStorageSegment class and then use the ledger AccountDimensionResolver resolve method to retrieve ledger dimension. Here’s an example of how that could be achieved:
//Dimension segement constant List const Name MAINACCOUNT = 'MainAccount'; const Name BUSINESSUNIT = 'BusinessUnit'; const Name CUSTOMERSEGMENT = 'CustomerSegment'; const Name PROJECT = 'Project'; const Name PRODUCT = 'Product'; const Name GROUPCODE = 'GroupCode'; const Name TARGET = 'Target';
public DimensionDynamicAccount getLedgerDimensionFromDisplayValues (CF1_DisplayValueTable _displayValueTable) { LedgerAccountDimensionResolver ledgerAccountDimensionResolver; DimensionStorage dimensionStorage; DimensionHierarchy dimensionHierarchy = DimensionHierarchy::find(DimensionHierarchy::getAccountStructure(MainAccount::findByMainAccountId(_displayValueTable.Account).RecId, Ledger::current()));
dimensionStorage = DimensionStorage::construct(); dimensionStorage.addAccountStructure(dimensionHierarchy.RecId); this.setSegments(dimensionStorage, dimensionHierarchy.RecId, _displayValueTable.Account, MAINACCOUNT); this.setSegments(dimensionStorage, dimensionHierarchy.RecId, _displayValueTable.Object1, BUSINESSUNIT); this.setSegments(dimensionStorage, dimensionHierarchy.RecId, _displayValueTable.Object2, CUSTOMERSEGMENT); this.setSegments(dimensionStorage, dimensionHierarchy.RecId, _displayValueTable.Object3, PROJECT); this.setSegments(dimensionStorage, dimensionHierarchy.RecId, _displayValueTable.Object4, PRODUCT); this.setSegments(dimensionStorage, dimensionHierarchy.RecId, _displayValueTable.Object5, GROUPCODE); this.setSegments(dimensionStorage, dimensionHierarchy.RecId, _displayValueTable.Object6, TARGET); ledgerAccountDimensionResolver = LedgerAccountDimensionResolver::newResolver(dimensionStorage.getComboDisplayValue(), dimensionHierarchy.Name); ledgerAccountDimensionResolver.parmDimensionFormat(DimensionHierarchyView::findByHierarchy(dimensionHierarchy.RecId).Segments); return ledgerAccountDimensionResolver.resolve(); } public void setSegments(DimensionStorage _dimensionStorage, DimensionHierarchyId _dimensionHierarchyId, DimensionValue _dimensionValue, Name _dimensionName) { DimensionAttribute dimensionAttribute = DimensionAttribute::findByName(_dimensionName); DimensionAttributeValue dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute, _dimensionValue);
if (_dimensionValue && dimensionAttributeValue && _dimensionHierarchyId && dimensionAttribute) { DimensionStorageSegment dimStorageSegment; dimStorageSegment = DimensionStorageSegment::construct( _dimensionValue, dimensionAttributeValue.RecId, dimensionAttributeValue.HashKey); _dimensionStorage.setSegment(DimensionHierarchyLevel::findByDimensionHierarchyAndDimAttribute(_dimensionHierarchyId, dimensionAttribute.RecId).Level, dimStorageSegment); } }
Example 5: Financial dimensions from display values in Dynamics 365
To retrieve a default dimension from the dimension segment display values you will need to use DimensionAttributeValueSetStorage class. Here’s an example of how this can be implemented:
public static DimensionDefault getDefaultDimensionFromDisplayValues(CF1_DisplayValueTable _displayValueTable) { //Dimension segement constant List const Name BUSINESSUNIT = 'BusinessUnit'; const Name CUSTOMERSEGMENT = 'CustomerSegment'; const Name PROJECT = 'Project'; const Name PRODUCT = 'Product'; const Name GROUPCODE = 'GroupCode'; const Name TARGET = 'Target'; DimensionAttributeValueSetStorage invoiceDAVSStorage; void addItem(DimensionAttributeValue _dav) { if (_dav) invoiceDAVSStorage.addItem(_dav); } invoiceDAVSStorage = new DimensionAttributeValueSetStorage(); addItem(DimensionAttributeValue::findByDimensionAttributeAndValue(DimensionAttribute::findByName(BUSINESSUNIT), _displayValueTable.Object1)); addItem(DimensionAttributeValue::findByDimensionAttributeAndValue(DimensionAttribute::findByName(CUSTOMERSEGMENT), _displayValueTable.Object2)); addItem(DimensionAttributeValue::findByDimensionAttributeAndValue(DimensionAttribute::findByName(PROJECT), _displayValueTable.Object3)); addItem(DimensionAttributeValue::findByDimensionAttributeAndValue(DimensionAttribute::findByName(PRODUCT), _displayValueTable.Object4)); addItem(DimensionAttributeValue::findByDimensionAttributeAndValue(DimensionAttribute::findByName(GROUPCODE), _displayValueTable.Object5)); addItem(DimensionAttributeValue::findByDimensionAttributeAndValue(DimensionAttribute::findByName(TARGET), _displayValueTable.Object6)); return invoiceDAVSStorage.save(); }
Figure 6: Retrieve Default Dimension in Dynamics 365
I hope this has given you some insight into the differences between dimension structure in Dynamics 365 for Operations [Enterprise Edition] versus Dynamics AX 2012. Stay tuned for more information and insights from 1ClickFactory on Dynamics 365 for Operations [Enterprise Edition]!