Note: A lot of this is written by Claude with directions from me. We ran into this issue while developing the MCP server.
The property list an exposed Generic Inquiry returns over OData is **neither the order
nor the exact set of columns you put in the Results Grid**, and I can't find anything in
the design tables that tells you what it *will* be. Asking in case I've missed it.
Say a GI's Results Grid holds three columns, in Sort Order: `Customer Name`,
`Order Nbr`, `Status`. What `$metadata` actually reports is something else:
- Any result column that is **also an entity key** is hoisted to the **front** of the list.
- Keys of the joined tables are **appended at the end even if you never added them** — this
part *is* documented ("*GI Access Through OData: General Information*").
- Where two columns produce the same name, one becomes `X` and the other `X_2` — and which
one keeps the bare name depends on **grid position**, not on the column.
- Inactive rows are skipped, and the order follows **Sort Order**, which is not Line Number.
So you can't read the grid and predict the output. And you can't recover it from the design
either:
- **`Caption` is only an override** and is NULL for most columns, so there's usually nothing
to match on.
- **`SchemaField`** is NULL for most rows and DAC-qualified where present (`INTran.RefNbr`),
so it never equals the bare property (`RefNbr`).
- The naming rule *is* documented — property names come from the field's **display name**,
with invalid symbols stripped (*Preparation of an Inquiry for Exposure* → "Supporting the
OData Specification"). But the display name isn't in `GIResult`: the `fieldName` field
exists and is **virtual**, so it comes back NULL over OData. (Filtering it says so
outright: *"Filter on '{0}' is not allowed because it is a virtual field."*)
Net effect: `$metadata` is the only source of truth, and any tool that needs to know *which
design column became which property* has to infer it positionally. That's uncomfortable for
two reasons. A wrong inference doesn't fail — it silently shifts every later column by one.
And because the `_2` suffix follows position, **editing a GI can move which column owns the
bare name**, which changes what an existing `$select=X` returns without any error.
Is the projection rule documented somewhere I've missed? If not, a paragraph in
"Supporting the OData Specification" stating where hoisted keys land, that ordering follows
Sort Order, that inactive rows are excluded, and how duplicate names are resolved would
remove the guesswork. Populating `GIResult.fieldName` would remove it entirely.