SAP / openui5

OpenUI5 lets you build enterprise-ready web applications, responsive to all devices, running on almost any browser of your choice.
http://openui5.org
Apache License 2.0
2.9k stars 1.23k forks source link

No key predicate known at `expanded navigation list item` #4057

Closed mgerzabek closed 1 month ago

mgerzabek commented 1 month ago

OpenUI5 version: 1.123.0

Browser/version (+device/version): Chrome 124.0.6367.208

Any other tested browsers/devices(OK/FAIL):

Description

In my controller I bind a master-detail view with:

this.getView().bindObject({
  path: `/Projects(${projectId})`,
  parameters: {
    expand: "contacts,settlements,postings"
  }
});

which leads to a GET Projects(132)?expand=contacts,settlements,postings HTTP/1.1,

that is fulfilled by this JSON response:

{
    "@odata.context": "https://****.***/odata/$metadata#Projects(contacts(),settlements(),postings())/$entity",
    "id": "132",
    …
    "settlements": [
        {
            "id": "101",
            …
        }
    ],
    "contacts": [],
    "postings": [
        {
            "id": "101",
            …
        },
        {
            "id": "2198",
            …
        },
        {
            "id": "2199",
            …
        }
    ]
}

I stripped all the content to only show that the structure from my odata v4 service is fine. Also my views are prepared with the necessary data (using sap.uxap.ObjectPageLayout), so at the first sight everything is fine.

But when I want to edit an expanded entity from postings, and want to access the context for this entity, I get the error No key predicate known at /Projects(132)/postings/2.

The navigation property in $metadata is declared as:

<NavigationProperty Name="postings" Type="Collection(io.pragmatiqu.Posting)" Nullable="true">
  <ReferentialConstraint Property="id" ReferencedProperty="project_id"/>
</NavigationProperty>

In the event handler of a sap.m.ColumnListItem I try to get the canonical path of the posting:

public onEditPosting(e: ListItemBase$DetailPressEvent): void {
  const item = e.getSource<ColumnListItem>();
  const context = <Context> item.getBindingContext();
  context.requestCanonicalPath().then((path) => {
    …
  }).catch((error) => {
    MessageBox.error("Eintrag kann zur Zeit nicht bearbeitet werden.");
  });

This always leads to the error:

2024-05-28 12:44:10.164500 No key predicate known at /Projects(132)/postings/2 - Error: /Projects(132)/postings/2: No key predicate known at /Projects(132)/postings/2
    at error (http://localhost:8080/resources/sap/ui/model/odata/v4/ODataMetaModel.js:1698:17)
    at http://localhost:8080/resources/sap/ui/model/odata/v4/ODataMetaModel.js:1838:7
    at eval (http://localhost:8080/resources/sap/ui/base/SyncPromise.js?eval:314:14)
    at call (http://localhost:8080/resources/sap/ui/base/SyncPromise.js?eval:63:4)
    at new SyncPromise (http://localhost:8080/resources/sap/ui/base/SyncPromise.js?eval:230:3)
    at SyncPromise.then (http://localhost:8080/resources/sap/ui/base/SyncPromise.js?eval:313:7)
    at http://localhost:8080/resources/sap/ui/model/odata/v4/ODataMetaModel.js:1830:47
    at Array.map (<anonymous>)
    at http://localhost:8080/resources/sap/ui/model/odata/v4/ODataMetaModel.js:1825:36
    at eval (http://localhost:8080/resources/sap/ui/base/SyncPromise.js?eval:314:14) sap.ui.model.odata.v4.ODataMetaModel

What is the expected result?

The string for the resolved promise should be /Postings(2199).

What happens instead?

The promise is rejected.

ThomasChadzelek commented 1 month ago

Can you please show the metadata of io.pragmatiqu.Posting, especially the section with its key?

mgerzabek commented 1 month ago

Hello @ThomasChadzelek,

And thank's for the instant reply. This is the shortened version of the posting:

<EntityType Name="Posting">
    <Key>
        <PropertyRef Name="id"/>
    </Key>
    <Property Name="id" Type="Edm.Int64" Nullable="false">
        <Annotation Term="Org.OData.Core.V1.Computed" Bool="true"/>
    </Property>
    <Property Name="user_id" Type="Edm.Int64" Nullable="false"/>
    <Property Name="project_id" Type="Edm.Int64" Nullable="false"/>
    <Property Name="date" Type="Edm.Date" Nullable="true"/>
    <Property Name="order" Type="Edm.Int64" Nullable="true" DefaultValue="1">
        <Annotation Term="Org.OData.Core.V1.ComputedDefaultValue" Bool="true"/>
    </Property>
    <Property Name="hours" Type="Edm.Decimal" Nullable="false"/>
    <Property Name="comment" Type="Edm.String" Nullable="false"/>
</EntityType>
ThomasChadzelek commented 1 month ago

That looks pretty well. But one thing strikes me now. You've said expand: "contacts,settlements,postings" - shouldn't that read $expand for V4? Maybe your service accepts it w/o the $, but the model will not properly understand it.

mgerzabek commented 1 month ago

You're right! With the $ in place everything works now as supposed. Thank you very much!

ThomasChadzelek commented 1 month ago

You're welcome!