X++ code to retrieve default dimensions (via individual selects)
Obviously this isn't a particularly efficient approach - it's expanded out like this for the sake of demonstration. In picture-form it may look similar to the following. Note the main tables involved, and the relationships between them:
I'll be interested in seeing how this affects reporting that works off direct SQL queries or cubes, as we now have to dynamically link tables based on the underlying source table (identified by DimensionAttribute.BackingEntityType). It could make things a bit tricky, and I suspect we'll have to rely more on generating datasets from within Ax, using the new data provider framework for SSRS.So an overview of the main tables involved is:
A unique combination of values used for default dimensions. This acts as a
container for a list of DimensionAttributeValueSetItem records, which link off
to the specific attribute and attribute value records.
This is similar in concept to the InventDim table in Ax2009, which stores unique combination of inventory dimension values. It uses a field called Hash, which stores a hash-code for all of the attached values. This is used by Ax when checking whether it needs to create a new entry, or use an existing one. (NB the dimension controllers rely heavily on server-side caching - If you're doing any investigation into the code it may help to disable this via code. Just make sure it's left as-is for production and testing environments).
This stores the individual attribute items (I would describe them more as the 'segments'), that make up a value set. This relates to the RecID of the
DimensionAttributeValueSet via the field of the same name.
Note that this table doesn't store the actual value. It points to an instance of DimensionAttributeValue (see below), which in-turn links back to the dimension value entitiy (eg Customer table).
This is a link between an attribute and a value.
The field EntityInstance points to the RecID of the underlying table/view. NB
the structure of this is normally that you create a view pointing to the table or tables you want to use for the dimension values. The view can be structured as normal with joins, relations, etc, but will typically only return three fields:
- Key - RecID of primary table
- Value - 'Code', such as customer account, item number, etc.
- Name - The description/name, eg The name on the customer address book entry.
The main attribute table. This will have an entry for 'department', 'cost centre', 'purpose', etc, as well as any other dimensions you define. Each DimensionAttribute points to a 'backing entity' type, which is the table/view id of the underlying data-source.
For 'custom value' dimensions (ie those that don't point to an existing table), this points indirectly to table DimensionFinancialTag.
* There's a slight caveat here. If the dimension points to a table like CustTable, how does Ax make sure that there is a corresponding entry in DimensionAttributeValue? The answer is that whenever the dimension value is referenced (for example by selecting it on a form), the system checks whether the entry exists, and if not, it's created. This occurs at:
And in addition, what if we're referencing the customer dimension, but the underlying customer record is deleted? If you look at CustTable.delete, you'll see a call to DimensionAttributeValue::updateForEntityValueDelete. This goes through any existing references to the corresponding DimensionAttributeValue and clears them. I suspect (at least I'd hope), that if any GL postings have already been made, you won't be able to remove the underlying record.
FormsThe class DimensionDefaultingController is used throughout the application to handle the display of default dimensions on master records (customer, suppliers, etc). If you look at the code in the following stack-trace, you'll see query logic similar to the sample at the beginning of this post.
The DimensionDefaultingController is created on the form, accepting the datasource and field (which in most cases will be DimensionDefault). On the datasource 'active' event, the controller iterates through the relevant dimension value set, and updates the controls. There's a lot more to cover with respect to how dimensions are displayed/updated from the UI - Look out for a future post.
Dynamics Ax Internals: Default dimension storage in Ax 2012