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

OData List binding error "Failed to enhance query" #4062

Closed angryBird87 closed 3 weeks ago

angryBird87 commented 4 weeks ago

OpenUI5 version: 1.123.2

Browser/version (+device/version): Firefox 126.0.1 (64-Bit)

Any other tested browsers/devices(OK/FAIL): Google Chrome 125.0.6422.142 (Official Build) (64-Bit) - FAIL

URL (minimal example if possible): http://localhost:8080/test/flpSandbox.html?sap-ui-xx-viewCache=false#objectmanagement-display&/object-details/2/5

Steps to reproduce the problem:

I am currently working with SAPUI5 (in my case I am not using OpenUI5, but posted here because both seem very similar) and developing an extension for the Web Client using the OData Model V4 for data retrieval. However, I am having trouble concerning data binding of a child collection. The datastructure I want to access (which partially works, except for the collection) looks as follows:

{
    "Code": "5",
    "OBJ_CUST_ADDRCollection": [
        {
            "Code": "5",
            "U_Address": "Construction site",
            "U_Street": "Sample Street 20",
            "U_City": "New York",
            "U_ZipCode": "1234",
            "U_CntctName": "John Doe"
        }
        //This array usually contains multiple entries which have the same schema as the one above.
    ]
}

Model configuration:

export const bpModel: ODataModel = new ODataModel({
        serviceUrl: `/b1s/v2/`,
        synchronizationMode: "None",
        operationMode: "Server",
        autoExpandSelect: true,
        earlyRequests: true,
        groupProperties : {
            UpdateGroup : {"submit" : "API"}
        },
        updateGroupId : updateGroupId
    });

To retrieve a specific entity, I have used an element binding to bind the bpModel to my view (the key is '5' in this instance):

view.bindElement({
                    path: `/OBJECT_CUSTOMER('${routingParams.customerObjCode}')`,
                    model: bpModelName
                });

I am using a fragment in my view, which contains the data binding to the collection "OBJ_CUST_ADDRCollection":

<core:FragmentDefinition 
    xmlns="sap.m"
    xmlns:mvc="sap.ui.core.mvc"
    xmlns:core="sap.ui.core">

        <VBox width="100%">
            <Title text="{i18n>objectAddresses}" class="sapUiSmallMarginBottom"/>
            <Table id="objAddresses" 
                mode="MultiSelect" 
                class="sapUiSmallMarginBottom"
                items="{
                    path: 'OBJ_CUST_ADDRCollection',
                    model: 'BP'
                }"
                sticky="HeaderToolbar,InfoToolbar,ColumnHeaders">
                <headerToolbar>
                    <OverflowToolbar>
                        <ToolbarSpacer/>
                        <Button icon="sap-icon://add" press="addAddress"/>
                        <Button icon="sap-icon://delete" press="deleteAddresses"/>
                        <Button icon="sap-icon://action-settings" press="changeObjAddressSettings"/>
                    </OverflowToolbar>
                </headerToolbar>
                <columns>
                    <Column>
                        <Text text="{i18n>objectAddressesID}"/>
                    </Column>
                    <Column>
                        <Text text="{i18n>objectAddressesStreetPOBox}"/>
                    </Column>
                    <Column>
                        <Text text="{i18n>objectAddressesLocation}"/>
                    </Column>
                    <Column>
                        <Text text="{i18n>objectAddressesZipCode}"/>
                    </Column>
                    <Column>
                        <Text text="{i18n>objectAddressesCntctAtLoc}"/>
                    </Column>
                </columns>
                <items>
                    <ColumnListItem>
                        <cells>
                            <Text text="{BP>U_Address}" />
                            <Text text="{BP>U_Street}" />
                            <Text text="{BP>U_City}" />
                            <Text text="{BP>U_ZipCode}" />
                            <Text text="{BP>U_CntctName}" />
                        </cells>
                    </ColumnListItem>
                </items>
            </Table>
        </VBox>
</core:FragmentDefinition>

What is the expected result?

The entire array "OBJ_CUST_ADDRCollection" should be retrieved by the ODataModel v4 and bound to the table outlined above. Each array entry should be displayed in its own row, as usual when using a table.

What happens instead?

Whenever this fragment (and the corresponding view) is loaded, I encounter the error "Failed to enhance query options for auto-$expand/$select as the child binding has query options, but its path 'OBJ_CUST_ADDRCollection' points to a structural property - {"$select":["U_Address","U_Street","U_City","U_ZipCode","U_CntctName"]} sap.ui.model.odata.v4.lib._Helper".

Any other information? (attach screenshot if possible)

When checking and manually testing the actual GET request sent by the OData model, I can see that the query parameter $select is used, which caused the request to fail. When I omitted this parameter (in my tests with Insomnia) the request worked.

At this point I have tried multiple things:

TeodorTaushanov commented 4 weeks ago

Hello, Thank you for sharing this finding. I've created an internal incident DINC0178235. The status of the issue will be updated here in GitHub.

Regards, Teodor

uhlmannm commented 3 weeks ago

Hi @angryBird87,

the support of collections of complex type by the v4.ODataModel is actually weak. The issue you experience is one thing but it sounds as if you would like to have some kind of editing. And editing with collections of complex type is currently not supported. Closing this gap would rather be a development request and it would not be possible quickly.

Instead you could use an own entity set for the addresses linked to the outer entity. The navigation property could be "contained" if your backend framework supports this. This setup with a separate (contained) entity set is well supported by the v4.ODataModel.

What do you think?

Best regards Mathias.

angryBird87 commented 3 weeks ago

Hello @uhlmannm,

thank you for your quick response. I have managed to solve my problem by now. I am no longer accessing UDOs but UDTs of type "No object", which are related to each other with foreign keys (which, to my understanding, is basically what you have suggested). This way, I don't have to use a deep create/deep update/deep read anymore.

As my problem is now solved, I will be closing this issue.

Thank you for your assistance.