Openui5: Odata.v4.OdataModel - hasPendingChnages error after failed submitChanges

Created on 2 Apr 2020  路  7Comments  路  Source: SAP/openui5

I use Odata V4 and I check if submitBatch method has been failed by checking the result of hasPendingChanges method.

this.getModel().submitBatch(BATCH_ID).then(function () {
                var bHasErrors = this.getModel().hasPendingChanges(BATCH_ID);
                if (bHasErrors) {
                    this._displayError();
                } else {
                   ...
            }.bind(this)).catch(function () {
                ...
            }.bind(this));
        },

If the result of hasPendingChanges is true, then batch failed(f.e. 'such value already exists in database') and error message appears. But after fixing duplicated value and resubmit the same error occurs.

The same issue described on SAP tutorials GitHub page, but it is still in process...

I tried to delete my batches(sGroupId = "TaskDetailBatch") with array of bathes, but this array always updates the previous condition:

image

P.S. The same isue was not resolved here

consulting

Most helpful comment

Hi @YahorStsefanovich ,

I do not get why you need another updateGroupId. I would expect something like the following:
Create case

  • The new context is created via ODataListBinding#create. (The list binding would preferably be the list binding you use for showing the task list.)
  • This new context is set as the binding context of the view for editing/creation.
  • When the user saves, submitBatch is triggered. The POST can either be successful (no pending changes, created promise is resolved) or not (the response to the POST should bear messages explaining why the POST was rejected, cf. Server Messages in OData V4 Model). The view would only be left if the created-Promise is resolved / there are no pending changes. (This depends on the design of the application. It could also have a central save and the view could be left without saving.)
    The important part with the failing save is that the backend provides understandable messages, preferably with a target to highlight the fields with the wrong input.
  • A Cancel/Delete button would allow the user to remove the transient context again. (With a global save, Cancel would not make much sense here as resetChanges would act globally on all changes.)

Edit case

  • The existing context is, e.g., the selected context of a list binding.
  • The context is set as the binding context of the view for editing/creation.
  • And then it works identically to the create case for the user.

Using several updateGroupIds does not seem like a good idea. Changes in different updateGroups lead to several batch requests. Is this really intended?

Best regards
Mathias.

All 7 comments

For checking if your batch context itself succeeded, the tutorials refer to the MessageModel:
https://ui5.sap.com/#/topic/b4f12660538147f8839b05cb03f1d478

As I found that quite cumbersome, especially as I wanted to use the default ErrorHandler we already get from the templates. And the ErrorHandler also uses the MessageModel.
I used the following for checking on my Create:

this.oAuthorListBinding = this.getModel().bindList('/Authors');
    this.oAuthorListBinding.attachCreateCompleted((oEvent) => {
        if (!oEvent.getParameter("success")) {
            this.oContext.destroy();
            this.getView().setBusy(false);
        }
    });

In which the oContext was the created object. And which had to be destroyed else, it would be resent on the next call.

I don't know whether you are doing creates or other type of calls, but maybe this can help a bit.

"P.S. The same isue was not resolved here" That other issue relates to V2, not V4, doesn't it?

Hi @vfweiss ,

I propose to rather use this.oContext.delete(); instead of this.oContext.destroy().

Best regards
Mathias.

Hi @YahorStsefanovich ,

I guess @vfweiss has already provided a possible solution for the create scenario.

In general, the promise of submitBatch is only rejected if the batch request itself has failed. The consequence is that this promise does not tell if changes were successfully persisted in the backend. However, it provides the point in time when an application could check itself. hasPendingChanges, which exists at context, binding and model with the respective scope, is one option.

I am not sure I understood your case correctly. You are trying to delete a number of records? What is the purpose of putting them into different batch requests?

Let me add two comments:
1) Changing requests are sent in changesets within the batch request. A changeset represents a logical unit of work and is either persisted as a whole or not at all. So far, changing requests are typically put into the same one changeset by the V4 model.
Furthermore, the processing of the batch request will stop once a request has failed. (The preference continue-on-error is not used by the V4 model. Also it must not be used when using v4.Context#requestSideEffects.)

2) With a backend that provides language dependent, understandable messages, see also Server Messages in OData V4 Model,
it should be sufficient to display the messages from the message model to the user. It would then not be required to understand in application code what failed but only that the save was not successful.

Best regards
Mathias.

Thank you all for answers!
Concerning to your question @uhlmannm, let me explain what I try to do:
1) I tried to create new tasks, but the view for creating new task and editing already existing task is the same one.
2) I can't create new task with already existing name.
3) My steps: create task "Test" -> success(no such names in DB) -> create task "Test" ->
->Error(such task already exists in DB) -> change "Test" to "Test1" -> task created on backend(no such names in DB) -> BUT hasPendingChanges(BATCH_ID) returns true (Why? You already explained it @uhlmannm, thank you)

So to fix problem I created another Batch ID:

...
if (this.getModel().hasPendingChanges(BATCH_ID)) {
    let oMockEntity = this.getView().bindList("/Tasks", null, null, null{
        $$updateGroupId: TEMP_BATCH_ID
    }).create(someDataObject);

    this.getModel().resetChanges(BATCH_ID);
    this.getView().setBindingContext(oMockEntity);
    this._displaySomeError();
} else {
    ...
}
...

Concerning to @vfweiss solution, it won't work in my case(as I understood) because when I destroy/delete context, I have error in other function calls so I need to create context again to fix it, but, actually, I don't sure when it should be done.

Hi @YahorStsefanovich ,

I do not get why you need another updateGroupId. I would expect something like the following:
Create case

  • The new context is created via ODataListBinding#create. (The list binding would preferably be the list binding you use for showing the task list.)
  • This new context is set as the binding context of the view for editing/creation.
  • When the user saves, submitBatch is triggered. The POST can either be successful (no pending changes, created promise is resolved) or not (the response to the POST should bear messages explaining why the POST was rejected, cf. Server Messages in OData V4 Model). The view would only be left if the created-Promise is resolved / there are no pending changes. (This depends on the design of the application. It could also have a central save and the view could be left without saving.)
    The important part with the failing save is that the backend provides understandable messages, preferably with a target to highlight the fields with the wrong input.
  • A Cancel/Delete button would allow the user to remove the transient context again. (With a global save, Cancel would not make much sense here as resetChanges would act globally on all changes.)

Edit case

  • The existing context is, e.g., the selected context of a list binding.
  • The context is set as the binding context of the view for editing/creation.
  • And then it works identically to the create case for the user.

Using several updateGroupIds does not seem like a good idea. Changes in different updateGroups lead to several batch requests. Is this really intended?

Best regards
Mathias.

Hi @YahorStsefanovich ,

I am closing the issue as there seems to be no further support required. Please open it again if my perception is wrong!

Best regards
Mathias.

Was this page helpful?
0 / 5 - 0 ratings