Skip to content

[Bug] **Generated @odata.bind navigation property casing doesn't match the actual lookup SchemaName when the column was created via the Dataverse Web API/metadata (not the classic maker-portal column designer)** #451

Description

@AdilsonCapaia

Summary

When a custom lookup column is created against Dataverse via the Web API( in my case) CreateAttribute metadata endpoint (e.g. through an MCP tool, script, or any non-maker-portal path) with SchemaName set equal to the all lowercase LogicalName (instead of the classic PascalCase-after-underscore convention the maker portal UI normally produces, ex: new_Account), the Code Apps data-source code generator still emits the classic PascalCase form for the corresponding @odata.bind key in the generated TypeScript model (ex: "trd_Order@odata.bind"), instead of introspecting the actual live metadata casing ("trd_order@odata.bind") in my concret case.

Because the generated interface is just a TypeScript type (no runtime validation), the project compiles and builds successfully, but any create()/update() call that populates the mis-cased bind property fails at runtime against the live Dataverse Web API with an OData "undeclared property" error, since Dataverse's OData endpoint is case-sensitive for navigation property names and only recognizes the real SchemaName casing.

Steps to Reproduce

  1. In a Dataverse environment, create a custom table with a custom lookup column using the Web API metadata endpoint directly (ex: POST .../EntityDefinitions(...)/Attributes) rather than the maker portal's column designer, specifying a display name like Order and letting SchemaName default to the same casing as LogicalName (all lowercase, e.g. trd_order) instead of the portal's usual trd_Order.
  2. In a Power Apps Code App project (@microsoft/power-apps-cli), add/refresh this table as a data source (pa app run / data source add & codegen).
  3. Open the generated model file, e.g. src/generated/models/<Table>Model.ts.
  4. Observe the generated interface emits the bind property using the classic PascalCase-after-underscore convention, e.g.:
    "trd_Order@odata.bind"?: string;
    "trd_Menu_Item@odata.bind"?: string;
  5. Call the generated service's create() (or update()) with that property populated, e.g.:
    Trd_orderlineitemsService.create({
      ...,
      'trd_Order@odata.bind': `/trd_orders(${orderId})`,
    });
  6. Observe the request fails against the live Dataverse Web API with an OData error similar to:
    Undeclared property 'trd_Order' found in JSON.
    

Expected Behavior

The generated @odata.bind key should match the lookup attribute's actual SchemaName/navigation-property as reported by Dataverse metadata ($metadata, or the associatednavigationproperty OData annotation returned on the corresponding _value field), regardless of the casing convention used when the attribute was created : in this repro case, "trd_order@odata.bind" / "trd_menu_item@odata.bind" (lowercase), which is what the live endpoint actually accepts.

Actual Behavior

Image

The generator assumes the classic maker-portal casing convention (capitalize the segment after each underscore) rather than reading the real navigation-property metadata, producing a bind key the live OData endpoint rejects. This silently passes TypeScript compilation and only fails at runtime, with no design-time warning.

Supporting Evidence

A live GET against trd_orderlineitems({id}) returns the following OData annotations, retrieved directly from Dataverse metadata for the record:

Attribute Name Value
_trd_order_value@Microsoft.Dynamics.CRM.associatednavigationproperty trd_order
_trd_order_value@Microsoft.Dynamics.CRM.lookuplogicalname trd_order
_trd_menu_item_value@Microsoft.Dynamics.CRM.associatednavigationproperty trd_menu_item
_trd_menu_item_value@Microsoft.Dynamics.CRM.lookuplogicalname trd_menuitem

The associatednavigationproperty value is the exact key Dataverse expects for @odata.bind on create/update : both confirmed lowercase (trd_order, trd_menu_item), never the PascalCase form (trd_Order, trd_Menu_Item) emitted by the generated model. (Note lookuplogicalname is a distinct annotation : it identifies the target table's logical name, e.g. trd_menuitem, not the attribute/nav-property name used for binding.) This proves the generator should read associatednavigationproperty (or the equivalent SchemaName from EntityDefinitions...Attributes) rather than deriving the bind key heuristically from the display/logical name.

Environment

  • @microsoft/power-apps-cli: 1.0.1
  • @microsoft/power-apps: 1.2.5
  • @microsoft/power-apps-vite: 1.0.2
  • Dataverse online environment
  • Affected columns: custom lookup attributes created via Dataverse Web API metadata calls (in this case through an MCP-based Dataverse tool), not the maker-portal column designer

Suggested Fix / Workaround

  • Codegen should resolve @odata.bind navigation-property names from the live $metadata (or the associatednavigationproperty annotation / EntityDefinitions...Attributes SchemaName) rather than deriving them heuristically from the display/logical name.
  • Workaround (used in this repro): manually patch the generated model file(s) to lowercase the affected @odata.bind keys to match the real schema, and keep call sites in sync.

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