Odata SAPUI5-将关联/外键更新为产品的另一个类别

Odata SAPUI5-将关联/外键更新为产品的另一个类别,odata,sapui5,Odata,Sapui5,我有一个简单的要求,即从SAPUI5客户端应用程序更新给定产品的“类别Id” 我的产品和类别数据库设计为: 类别表包含ID、名称和说明。 产品表具有ID、名称、说明和类别ID。类别ID是类别表的外键,是此表中的必填列 使用CRUD操作实现OData服务。这些操作使用postman和json输入请求进行测试。创建(发布)请求示例: { “名称”:“12月18日的iPad”, “说明”:“2019年12月18日”, "Category@odata.bind“:1} 补丁请求:(用于更新) { “说明

我有一个简单的要求,即从SAPUI5客户端应用程序更新给定产品的“类别Id”

我的产品和类别数据库设计为: 类别表包含ID、名称和说明。 产品表具有ID、名称、说明和类别ID。类别ID是类别表的外键,是此表中的必填列

使用CRUD操作实现OData服务。这些操作使用postman和json输入请求进行测试。创建(发布)请求示例:

{ “名称”:“12月18日的iPad”, “说明”:“2019年12月18日”, "Category@odata.bind“:1}

补丁请求:(用于更新)

{ “说明”:“笔记本基本型,1.7GHz-15 XGA-1024MB DDR2 SDRAM-40GB-更新版”, "Category@odata.bind“:2}

我正在使用SAPUI5 sap.m.表格显示产品。表的列表绑定在记录(项)发生任何更改时发送自动请求。在此过程中,它只发送不带类别id的产品信息

当我想更改类别id时,这让我很烦恼。比如说,我的表列表绑定是“{/Products}”。 如果我对类别ID使用绑定“{Category/ID}”,它将发送对类别实体的更新请求

我的请求应该是这样的:

{“名称”:“名称1”Category@odata.bind“:2}

我们如何在SAPUI5中实现这一点

下面是重要的代码

View.xml

   <mvc:View
    controllerName="sap.ui.core.tutorial.odatav4.controller.ProductsController"
    displayBlock="true"
    xmlns:core="sap.ui.core"
    xmlns="sap.m"
    xmlns:mvc="sap.ui.core.mvc">
    <VBox>
        <items>
            <Table
                id="productsTable"
                growing="true"
                growingThreshold="3"
                items="{
                        path: '/Products',
                        parameters: {
                            $count: true,
                            'expand': 'Category'
                        }, 
                        events:{
                            change: '.onChangeHandler'
                        }
                    }"
                mode="SingleSelectLeft">
                <!--  ,$$updateGroupId : 'peopleGroup' -->
            <headerToolbar>
                <OverflowToolbar>
                    <content>
                        <ToolbarSpacer/>
                        <SearchField
                            id="searchField"
                            width="20%"
                            placeholder="{i18n>searchFieldPlaceholder}"
                            enabled="{= !${appView>/hasUIChanges}}"
                            search=".onSearch"/>
                        <Button
                            id="addUserButton"
                            icon="sap-icon://add"
                            tooltip="{i18n>createButtonText}"
                            press=".onCreate">
                            <layoutData>
                                <OverflowToolbarLayoutData priority="NeverOverflow"/>
                            </layoutData>
                        </Button>
                        <Button
                            id="deleteUserButton"
                            icon="sap-icon://delete"
                            tooltip="{i18n>deleteButtonText}"
                            press=".onDelete">
                            <layoutData>
                                <OverflowToolbarLayoutData priority="NeverOverflow"/>
                            </layoutData>
                        </Button>
                        <Button
                            id="refreshUsersButton"
                            icon="sap-icon://refresh"
                            enabled="{= !${appView>/hasUIChanges}}"
                            tooltip="{i18n>refreshButtonText}"
                            press=".onRefresh"/>
                        <Button
                            id="sortUsersButton"
                            icon="sap-icon://sort"
                            enabled="{= !${appView>/hasUIChanges}}"
                            tooltip="{i18n>sortButtonText}"
                            press=".onSort"/>
                    </content>
                </OverflowToolbar>
            </headerToolbar>
            <columns>
                <Column id="userNameColumn">
                    <Text text="{i18n>userNameLabelText}"/>
                </Column>
                <Column id="firstNameColumn">
                    <Text text="{i18n>firstNameLabelText}"/>
                </Column>
                <Column id="lastNameColumn">
                    <Text text="{i18n>lastNameLabelText}"/>
                </Column>
                <Column id="tierIdColumn">
                    <Text text="{i18n>tierIdLabelText}"/>
                </Column>
                <!-- <Column id="tierIdColumn2">
                    <Text text="Category Id placeholder" />
                </Column> -->
            </columns>
            <items>
                <ColumnListItem id="table_col">
                    <cells>
                        <Input
                            value="{ID}"
                            valueLiveUpdate="true"
                            liveChange=".onInputChange"/>
                    </cells>
                    <cells>
                        <Input
                            value="{Name}"
                            liveChange=".onInputChange"/>
                    </cells>
                    <cells>
                        <Input
                            value="{Description}"
                            liveChange=".onInputChange"/>
                    </cells>
                    <cells>
                        <Input value="{Category/ID}" liveChange=".onInputChange"/>
                    </cells>
                </ColumnListItem>
            </items>
        </Table>
                <!-- <footer> -->
                    <Toolbar visible="{appView>/hasUIChanges}">
                        <ToolbarSpacer/>
                        <Button
                            id="saveButton"
                            type="Emphasized"
                            text="{i18n>saveButtonText}"
                            enabled="{= ${message>/}.length === 0 &amp;&amp; ${appView>/usernameEmpty} === false }"
                            press=".onSave"/>
                        <Button
                            id="doneButton"
                            text="{i18n>cancelButtonText}"
                            press=".onResetChanges"/>
                    </Toolbar>
                <!-- </footer> -->
            </items>
    </VBox>
</mvc:View> 

它在SAPUI5中不受支持还是一项特殊要求?在SAPUI5中不受支持还是一项特殊要求?
sap.ui.define([
    "sap/ui/core/mvc/Controller",
    "sap/m/MessageToast",
    "sap/m/MessageBox",
    "sap/ui/model/Sorter",
    "sap/ui/model/Filter",
    "sap/ui/model/FilterOperator",
    "sap/ui/model/FilterType",
    "sap/ui/model/json/JSONModel",
    "sap/base/Log"
], function (Controller, MessageToast, MessageBox, Sorter, Filter, FilterOperator, FilterType, JSONModel, Log) {
    "use strict";

    var CATEGORIES_TABLE_ID = "productsTable";

    return Controller.extend("sap.ui.core.tutorial.odatav4.controller.ProductsController", {
        /**
         *  Hook for initializing the controller
         */
        onInit : function () {
            var oMessageManager = sap.ui.getCore().getMessageManager(),
                oMessageModel = oMessageManager.getMessageModel(),
                oMessageModelBinding = oMessageModel.bindList("/", undefined, [],
                    new Filter("technical", FilterOperator.EQ, true)),
                oViewModel = new JSONModel({
                    busy : false,
                    hasUIChanges : false,
                    usernameEmpty : true,
                    order : 0
                });
            this.getView().setModel(oViewModel, "appView");
            this.getView().setModel(oMessageModel, "message_layers");

            oMessageModelBinding.attachChange(this.onMessageBindingChange, this);
            this._bTechnicalErrors = false;

            // Can I attach an event listener to include category_id before submit
        },


        /* =========================================================== */
        /*           begin: event handlers                             */
        /* =========================================================== */

        onChangeHandler: function(oEvent){
            var eventName = oEvent.getParameter("reason");
            console.log("Change: Event raised: " + eventName + ", timestamp = " + new Date().getTime());

        },

        /**
         * Create a new entry.
         */
        onCreate : function () {
            var oList = this.byId( CATEGORIES_TABLE_ID );
            var oBinding = oList.getBinding("items"),
                // Create a new entry through the table's list binding
                oContext = oBinding.create({
                    "ID" : null,
                    "Name" : "",
                    "Description" : "",
                    "Category@odata.bind": 1
                });

            this._setUIChanges(true);
            this.getView().getModel("appView").setProperty("/usernameEmpty", true);

            // Select and focus the table row that contains the newly created entry
            oList.getItems().some(function (oItem) {
                if (oItem.getBindingContext() === oContext) {
                    oItem.focus();
                    oItem.setSelected(true);
                    return true;
                }
            });
        },

        /**
         * Delete an entry.
         */
        onDelete : function () {
            var oSelected = this.byId( CATEGORIES_TABLE_ID ).getSelectedItem();

            if (oSelected) {
                oSelected.getBindingContext().delete("$direct").then(function () {
                    MessageToast.show(this._getText("deletionSuccessMessage"));
                }.bind(this), function (oError) {
                    MessageBox.error(oError.message);
                });
            }
        },

        /**
         * Lock UI when changing data in the input controls
         * @param {sap.ui.base.Event} oEvt - Event data
         */
        onInputChange : function (oEvt) {
            if (oEvt.getParameter("escPressed")) {
                this._setUIChanges();
            } else {
                this._setUIChanges(true);
                // Check if the id in the changed table row is empty and set the appView property accordingly
                if (oEvt.getSource().getParent().getBindingContext().getProperty("ID")) {
                    this.getView().getModel("appView").setProperty("/usernameEmpty", false);
                }
            }
        },

        /**
         * Refresh the data.
         */
        onRefresh : function () {
            var oBinding = this.byId( CATEGORIES_TABLE_ID ).getBinding("items");

            if (oBinding.hasPendingChanges()) {
                MessageBox.error(this._getText("refreshNotPossibleMessage"));
                return;
            }
            oBinding.refresh();
            MessageToast.show(this._getText("refreshSuccessMessage"));
        },

        /**
         * Reset any unsaved changes.
         */
        onResetChanges : function () {
            this.byId( CATEGORIES_TABLE_ID ).getBinding("items").resetChanges();
            this._bTechnicalErrors = false; // If there were technical errors, cancelling changes resets them.
            this._setUIChanges(false);
        },

        /**
         * Reset the data source.
         */
        onResetDataSource : function () {
            var oModel = this.getView().getModel(),
                oOperation = oModel.bindContext("/ResetDataSource(...)");

            oOperation.execute().then(function () {
                    oModel.refresh();
                    MessageToast.show(this._getText("sourceResetSuccessMessage"));
                }.bind(this), function (oError) {
                    MessageBox.error(oError.message);
                }
            );
        },

        /**
         * Save changes to the source.
         */
        onSave : function () {
            var fnSuccess = function () {
                this._setBusy(false);
                MessageToast.show(this._getText("changesSentMessage"));
                this._setUIChanges(false);
            }.bind(this);

            var fnError = function (oError) {
                this._setBusy(false);
                this._setUIChanges(false);
                MessageBox.error(oError.message);
            }.bind(this);

            this._setBusy(true); // Lock UI until submitBatch is resolved.
            this.getView().getModel().submitBatch("peopleGroup").then(fnSuccess, fnError);
            this._bTechnicalErrors = false; // If there were technical errors, a new save resets them.
        },

        /**
         * Search for the term in the search field.
         */
        onSearch : function () {
            var oView = this.getView(),
                sValue = oView.byId("searchField").getValue(),
                oFilter = new Filter("description", FilterOperator.Contains, sValue);

            oView.byId( CATEGORIES_TABLE_ID ).getBinding("items").filter(oFilter, FilterType.Application);
        },

        /**
         * Sort the table according to the Description.
         * Cycles between the three sorting states "none", "ascending" and "descending"
         */
        onSort : function () {
            var oView = this.getView(),
                aStates = [undefined, "asc", "desc"],
                aStateTextIds = ["sortNone", "sortAscending", "sortDescending"],
                sMessage,
                iOrder = oView.getModel("appView").getProperty("/order");

            // Cycle between the states
            iOrder = (iOrder + 1) % aStates.length;
            var sOrder = aStates[iOrder];

            oView.getModel("appView").setProperty("/order", iOrder);
            oView.byId( CATEGORIES_TABLE_ID ).getBinding("items").sort(sOrder && new Sorter("description", sOrder === "desc"));

            sMessage = this._getText("sortMessage", [this._getText(aStateTextIds[iOrder])]);
            MessageToast.show(sMessage);
        },

        onMessageBindingChange : function (oEvent) {
            var aContexts = oEvent.getSource().getContexts(),
                aMessages,
                bMessageOpen = false;

            if (bMessageOpen || !aContexts.length) {
                return;
            }

            // Extract and remove the technical messages
            aMessages = aContexts.map(function (oContext) {
                return oContext.getObject();
            });
            sap.ui.getCore().getMessageManager().removeMessages(aMessages);

            this._setUIChanges(true);
            this._bTechnicalErrors = true;
            MessageBox.error(aMessages[0].message, {
                id : "serviceErrorMessageBox",
                onClose : function () {
                    bMessageOpen = false;
                }
            });

            bMessageOpen = true;
        },

        fnFormatter: function(text, key) {
            var sText = "";

            if (text && key) {
                sText += (text + " (" + key + ")");
            } else if (text) {
                sText += text;
            } else if (key) {
                sText += key;
            }

            return sText;
        },


        /* =========================================================== */
        /*           end: event handlers                               */
        /* =========================================================== */


        /**
         * Convenience method for retrieving a translatable text.
         * @param {string} sTextId - the ID of the text to be retrieved.
         * @param {Array} [aArgs] - optional array of texts for placeholders.
         * @returns {string} the text belonging to the given ID.
         */
        _getText : function (sTextId, aArgs) {
            return this.getView().getModel("i18n").getResourceBundle().getText(sTextId, aArgs);
        },

        /**
         * Set hasUIChanges flag in View Model
         * @param {boolean} [bHasUIChanges] - set or clear hasUIChanges
         * if bHasUIChanges is not set, the hasPendingChanges-function of the OdataV4 model determines the result
         */
        _setUIChanges : function (bHasUIChanges) {
            if (this._bTechnicalErrors) {
                // If there is currently a technical error, then force 'true'.
                bHasUIChanges = true;
            } else if (bHasUIChanges === undefined) {
                bHasUIChanges = this.getView().getModel().hasPendingChanges();
            }
            var oModel = this.getView().getModel("appView");
            oModel.setProperty("/hasUIChanges", bHasUIChanges);
        },

        /**
         * Set busy flag in View Model
         * @param {boolean} bIsBusy - set or clear busy
         */
        _setBusy : function (bIsBusy) {
            var oModel = this.getView().getModel("appView");
            oModel.setProperty("/busy", bIsBusy);
        }

        ,onSelect: function(oEvt){
            var selectedCategoryId = oEvt.getSource().getSelectedKey();
            this.byId("category_id_4_product").setValue( selectedCategoryId );
        },
        /**
         * Copies category_id value from placeholder column to actual column
         */
        _copyToInputField: function( oCells, value ){
            for( var i=0; i < oCells.length; i++ ){
                if( oCells[i].getId().match( "category_id_actual" ) ){
                    oCells[i].setValue( value );
                }
            }
        }
    });
});
{
    "_version": "1.12.0",
    "sap.app": {
        "id": "sap.ui.core.tutorial.odatav4",
        "type": "application",
        "i18n": "i18n/i18n.properties",
        "applicationVersion": {
            "version": "1.0.0"
        },
        "title": "{{appTitle}}",
        "description": "{{appDescription}}",
        "dataSources": {
            "default": {
                "uri": "/DemoService/DemoService.svc/",
                "type": "OData",
                "settings": {
                    "odataVersion": "4.0"
                }
            }
        }
    },
    "sap.ui": {
        "technology": "UI5",
        "deviceTypes": {
            "desktop": true,
            "tablet": true,
            "phone": true
        }
    },
    "sap.ui5": {
        "rootView": {
            "viewName": "sap.ui.core.tutorial.odatav4.view.App",
            "type": "XML",
            "async": true,
            "id": "appView"
        },
        "dependencies": {
            "minUI5Version": "1.48.0",
            "libs": {
                "sap.m": {},
                "sap.ui.core": {},
                "sap.ui.layout": {}
            }
        },
        "contentDensities": {
            "compact": true,
            "cozy": true
        },
        "handleValidation": true,
        "models": {
            "i18n": {
                "type": "sap.ui.model.resource.ResourceModel",
                "settings": {
                    "bundleName": "sap.ui.core.tutorial.odatav4.i18n.i18n"
                }
            },
            "": {
                "dataSource": "default",
                "settings": {
                    "autoExpandSelect": true,
                    "operationMode": "Server",
                    "groupId": "$direct",
                    "synchronizationMode": "None"
                }
            }
        }
    }
}