Skip to content

[Bug] Suffix ***name virtual fields for lookups are generated as if they were real Dataverse columns, but no such attribute exists, the display name only ever exists as a FormattedValue annotation on the lookup itself #455

Description

@AdilsonCapaia

Title

Suffix *name virtual/mirror fields for lookups (e.g. trd_accountname, trd_truckname) are generated as if they were real Dataverse columns, but no such attribute exists, the display name only ever exists as a FormattedValue annotation on the lookup itself

Summary

For lookup columns, Dataverse exposes the related record's display name as a FormattedValue annotation attached to the lookup attribute itself (e.g. the raw record's trd_account attribute carries both the GUID and a FormattedValue of "BNP Paribas"). It does not create a separate, independently queryable attribute like trd_accountname for this purpose, that field simply doesn't exist anywhere in the table's real schema.

The Code Apps CLI's schema/type generator nonetheless synthesizes a sibling <lookup>name field (e.g. trd_accountname, trd_truckname, trd_contactname) for every lookup and adds it to the generated TypeScript type and JSON schema, making it look like a normal, populated string column. At runtime this field is always undefined/empty, because there is nothing on the wire (or in Dataverse metadata) to populate it from - the generator invented an attribute that Dataverse never creates.

Steps to Reproduce

  1. In a Dataverse table, add a lookup column (custom or standard) pointing to another table, e.g. trd_accountaccount.
  2. In a Power Apps Code App project, add/refresh this table as a data source and inspect the generated schema, e.g. .power/schemas/dataverse/<table>.Schema.json. Observe a synthesized field for the lookup's "name," e.g.:
    "trd_accountname": {
      "x-ms-dataverse-attribute": "trd_accountname",
      "x-ms-schema-name": "trd_AccountName",
      "x-ms-read-only": true
    }
  3. Confirm this field does not correspond to any real column: query the table's actual attribute list (e.g. via the Dataverse metadata/describe tooling) - trd_accountname is not present; only the lookup itself (trd_account) exists.
  4. Retrieve a record for this table that has the lookup populated with a valid, resolvable related record (e.g. confirm via SQL or the model-driven app that the Account lookup is genuinely set to "BNP Paribas").
  5. Pull the raw record data directly from Dataverse (e.g. via an SDK-style/organization-service record dump). Observe the related record's name is delivered as the FormattedValue of the trd_account key itself - there is no separate trd_accountname key anywhere in the record's attributes or formatted values.
  6. In the Code App, call the generated service's getAll()/get() for that table and read the trd_accountname field off the returned typed object.
  7. Observe the field is undefined/empty in the app, despite the lookup (trd_account) being valid and resolving to a real, named record.

Expected Behavior

Either:

  • (a) the generator should not synthesize a non-existent <lookup>name field at all, or
  • (b) if it does synthesize one for developer convenience, it should populate it at runtime from the lookup attribute's own FormattedValue/@OData.Community.Display.V1.FormattedValue annotation (the only place this data actually exists), so the convenience field behaves as documented.

Actual Behavior

The generated type/schema includes a <lookup>name field that looks like a normal, dependable string property, but it is never populated - it silently returns undefined regardless of whether the lookup is set, because Dataverse never emits a matching attribute or annotation under that name.

Supporting Evidence

  • Dataverse-side verification (SQL join) confirms the lookup and its target record both exist and are correctly linked - e.g. Order "Crêpes de Paris - 03/09/2026 17:49:01" has trd_account resolving to real Account "BNP Paribas" and trd_truck resolving to real Food Truck "Crêpes de Paris". Also confirmed directly in the model-driven app form (Account/Truck lookups clearly populated).
  • A raw record dump for that same order shows the related names delivered on the lookup's own key, not on any *name sibling:
    Attributes:      "trd_account": {Name: "BNP Paribas"}, "trd_truck": {Name: "Crêpes de Paris"}
    FormattedValues: "trd_account": "BNP Paribas",         "trd_truck": "Crêpes de Paris"
    
    No trd_accountname or trd_truckname key is present anywhere in the record.
  • The table's real column list (from Dataverse metadata) contains only trd_account, trd_contact, trd_truck as lookups - no trd_accountname/trd_contactname/trd_truckname columns exist.
  • The generated schema (orders.Schema.json) nonetheless lists these fabricated fields with a dual-casing pattern also seen elsewhere in this generator (x-ms-dataverse-attribute: trd_accountname vs. guessed x-ms-schema-name: trd_AccountName), suggesting the same underlying convention-guessing logic that produces the separately-reported @odata.bind casing bug is also responsible for inventing these non-existent mirror fields.

Environment

  • @microsoft/power-apps-cli: 1.0.1
  • @microsoft/power-apps: 1.2.5
  • @microsoft/power-apps-vite: 1.0.2
  • Dataverse online environment
  • Reproduced with both custom lookups (trd_account, trd_truck, created via Dataverse Web API metadata calls rather than the maker-portal column designer) - root cause likely generic to how the generator handles all lookup columns, not specific to custom vs. standard.

Suggested Fix / Workaround

  • The generator should stop assuming a <lookup>name sibling attribute exists for every lookup. If retained for developer convenience, it should be populated from the lookup's own FormattedValue annotation at runtime, not treated as an independent schema field.
  • Workaround: don't rely on the generated *name fields. Read the raw lookup GUID (trd_account, trd_truck, etc.) and resolve display names client-side against a small id→name map loaded once from the related data source (Accounts, Food Trucks, etc.).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions