Financial Dimensions in D365 Finance: How They Really Work
Financial dimensions are the part of Dynamics 365 Finance that everyone uses and few truly understand. Cost center, department, business unit, project — they tag every transaction and drive every meaningful report. Then a developer opens the data model, sees DimensionAttributeValueCombination joined to four other Dimension* tables, and quietly backs away. Let us make this concrete.
Two kinds of dimensions
There are exactly two flavours, and confusing them causes most dimension bugs.
- Default dimensions are a set of dimension values attached to a master record or line — a vendor, a fixed asset, a purchase line. They answer "what tags should transactions inherit from here?"
- Ledger dimensions are a main account plus its dimensions, combined into one accounting string. They answer "exactly which account did this voucher hit?"
A purchase order line carries a default dimension. When it posts, the framework merges that default dimension with the main account to produce the ledger dimension on the voucher. Same values, different purpose, different storage.
Where the values actually live
Every unique combination of dimension values is stored once in DimensionAttributeValueCombination (DAVC) and referenced by RecId. The supporting cast:
| Table | Holds |
|---|---|
DimensionAttribute | The dimension definitions (Department, CostCenter…) |
DimensionAttributeValue | A single value for one attribute (CostCenter "CC010") |
DimensionAttributeValueCombination | A full combination (the accounting string) |
DimensionAttributeValueSet | A set of values for default dimensions |
DimensionAttributeLevelValue | The exploded per-attribute rows for a combination |
The LedgerDimension and DefaultDimension fields you see on tables are just RecId pointers into this structure. That indirection is why you cannot read a cost center with a simple field access.
Reading dimensions in X++
To get a human-readable value out of a default dimension, walk the value set:
public static str getDimensionValue(
DimensionDefault _defaultDimension, str _dimensionName)
{
DimensionAttributeValueSetItem setItem;
DimensionAttributeValue dimValue;
DimensionAttribute dimAttr;
select firstonly Value from setItem
where setItem.DimensionAttributeValueSet == _defaultDimension
join RecId from dimValue
where dimValue.RecId == setItem.DimensionAttributeValue
join Name from dimAttr
where dimAttr.RecId == dimValue.DimensionAttribute
&& dimAttr.Name == _dimensionName;
return setItem.DisplayValue;
}
Building a default dimension in code
The supported way to create a combination is the DimensionDefaultingService / DimensionAttributeValueSetStorage helper, never hand-inserting into DAVC:
public static DimensionDefault buildDefaultDimension(
container _attrNames, container _values)
{
DimensionAttributeValueSetStorage storage =
new DimensionAttributeValueSetStorage();
for (int i = 1; i <= conLen(_attrNames); i++)
{
DimensionAttribute attr =
DimensionAttribute::findByName(conPeek(_attrNames, i));
if (attr.RecId)
{
DimensionAttributeValue dimValue =
DimensionAttributeValue::findByDimensionAttributeAndValue(
attr, conPeek(_values, i), false, true);
storage.addItem(dimValue);
}
}
return storage.save();
}
addItem plus save() deduplicates against existing combinations for you, so you never create orphan rows.
Account structures and advanced rules
What combinations are valid is governed by account structures and advanced rules, configured under General ledger > Chart of accounts > Structures. An account structure says "for main accounts 6000–6999, Department and CostCenter are required, BusinessUnit is blank." Advanced rules layer conditional dimensions on top — "if Department is Sales, also require SalesRegion."
This is why a voucher posting can fail with "the dimension combination is not valid": the values exist, but the account structure does not permit that shape for that main account. When you build ledger dimensions in code, validate against the active structure or the posting will reject them.
Reporting reality
Financial reporting (the Management Reporter successor) and Power BI both read the exploded DimensionAttributeLevelValue rows, which is why dimensions you populate correctly "just appear" in reports. If a dimension shows blank in reports but looks fine on the form, the usual culprit is a default dimension that was never merged into the ledger dimension at posting time — the report reads the voucher, and the voucher never got the tag.
Once you internalize default vs ledger and combinations stored once by RecId, the rest of the model stops being intimidating and starts being predictable.
Keep reading
Dual-Write Dropped My Field and Reported Success
Why a dual-write map can complete with zero errors while a custom F&O field never lands in Dataverse — staging tables, unpublished maps, and change tracking after a schema change.
OData 429s from F&O: What Actually Throttles You
HTTP 429 from Dynamics 365 Finance & Operations is usually the query shape, not the request count — cross-company scans, $filter that cannot seek, $batch that still burns SQL, and why retrying harder makes month-end worse.
SysTest in D365 F&O: Unit Tests That Survive a Platform Update
How to write X++ SysTest cases that isolate tables, skip UI, and stay green after Microsoft ships a new PU — without turning the suite into a 40-minute tax.
Feature Management in D365 Finance and Operations: Flags, States, and Custom Features
How the D365 F&O Feature management workspace works, what feature states mean for ALM, and how to ship your own X++ features behind flags.
D365 F&O Data Entities: Composite, Computed, and Virtual Fields Explained
Data entities look like simple tables until you need a nested import, a derived column, or a field with no storage. Knowing the three advanced shapes is what makes integrations actually work.
Extending Data Entities in D365 Finance & Operations Without Breaking Upgrades
Add fields, computed columns, and validation to standard D365 Finance & Operations data entities the upgrade-safe way — with X++ examples and the staging-table traps to avoid.
Newsletter
New posts, straight to your inbox
One email per post. No spam, no tracking pixels, unsubscribe anytime.
Comments
- No comments yet. Be the first.