Deferred Groups and Change Groups in SAPUI5

This blog post is about Deferred Groups and Change Groups. If not explicitly disabled, the sap.ui.model.odata.v2.ODataModel uses batch processing. In batch processing the ODataModel sends one or more OData requests in a single $batch http request. Using the so called groupId you can bundle specific OData requests in different $batch requests. This lets you optimize your data management in your application.

A groupId can be Immediate or Deferred.

Immediate
The OData requests created within a JavaScript function are collected and sent in a $batch request in a timeout immediately after the current call stack is finished.

Deferred
The OData requests are stored, and the $batch request for them is only sent when the method submitChanges of the ODataModel gets called with the corresponding groupId as parameter.

Deferred Groups

The default deferred group is “changes”. You can check it via getDeferredGroups.

this.getModel().getDeferredGroups();
//Expected output: ['changes']

You can define groups via setDeferredGroups.

this.getModel().setDeferredGroups(["a", "b"]);
this.getModel().getDeferredGroups();
//Expected output: ['a', 'b']

🛎️ Important

If you overwrite the default deferred group “changes” you may experience immediate $batch requests. That’s cause you “destroyed” the default settings. More about this in Change Groups.

Usually you want to add a group, but not define all of them or overwrite existing ones. For this i use the following function.

_createGroupId

        _createGroupId: function (sGroupId) {
            var oServiceModel = this.getView().getModel(), //may adjustment necessary
                aDeferredGroup = oServiceModel.getDeferredGroups();

            //Add a new GroupId
            if (!aDeferredGroup.includes(sGroupId)) {
                aDeferredGroup.push(sGroupId);
                oServiceModel.setDeferredGroups(aDeferredGroup);
            }
        }

Example

this.getModel().getDeferredGroups();
//Expected output: ['changes']
this._createGroupId("a");
this.getModel().getDeferredGroups();
//Expected output: ['changes', 'a']
this._createGroupId("a");
this.getModel().getDeferredGroups();
//Expected output: ['changes', 'a']
this._createGroupId("b");
this.getModel().getDeferredGroups();
//Expected output: ['changes', 'a', 'b']

Change Groups

By default every OData request will be stored in the deferred group “changes”. You can check it via getChangeGroups.

this.getModel().getChangeGroups();
//Expected output: {"*":{"groupId":"changes"}}

🛎️ Important

As mentioned above, if you overwrite the default deferred group “changes” you may experience immediate $batch requests. That’s cause by default every OData requests will be assigned to the groupId “changes”. If the group is not declared as an deferred group, its immediate.

If you just declare a new deferred group nothing changes. You have to code that specific changes should be bundled in the added deferred group. For that you can use setChangeGroups.

The following coding defines two new deferred groups. Every change in an entity of the EntitySetA should be captured in the group “groupForEntitySetA”. Every change in an Entity of the EntitySetB should be captured in the group “groupForEntitySetB”. This allows seperate data processing of the two entitysets.

			this._createGroupId("groupForEntitySetA");
			this._createGroupId("groupForEntitySetB");
			this._oServiceModel.setChangeGroups({
				"EntitySetA": {
					groupId: "groupForEntitySetA"//,
					//changeSetId: "A" //ID of a ChangeSet which bundles the changes for the entity type.
					//single: true //Defines if every change will get an own change set (defaults to true)
				},
				"EntitySetB": {
					groupId: "groupForEntitySetB"//,
					//changeSetId: "B" //ID of a ChangeSet which bundles the changes for the entity type.
					//single: true //Defines if every change will get an own change set (defaults to true)
				}
			});

Submit Changes

When working with deferred groups the $batch request is only sent when the method submitChanges gets called. If you do not specify a batch group ID when calling submitChanges, all deferred batch groups are submitted.

var oServiceModel = this.getModel();

oServiceModel.submitChanges({
	groupId: "groupForEntitySetA",
	success: function(oResponse) {
		//do sth. (process batch responses)
	}.bind(this),
	error: function(oErr) {
		//do sth. (error handling)
	    //busi exceptions in $batch are handled as success
        //only dumps/technical errors are handled as error
	}.bind(this)

});

Recommendation

Check out the following code snippet: How to process errors in batch responses.

Other ways to set the groupId

Apart from the method setChangeGroups, there are many other ways to assign a groupId to an OData request.

createEntry
If you create an data entry via createEntry you can pass the groupId as a parameter. This way you can handle specific OData create requests seperately if needed.

        _createDraft: function () {
            var oServiceModel = this.getView().getModel();
            var oContext = oServiceModel.createEntry("CarrierCollection", {
                groupId: this._createGroupId("CarrierCreation"),
                properties: {
                    carrid: "",
                    CARRNAME: "",
                    CURRCODE: "EUR",
                    URL: ""
                }
            });

            return oContext.getPath();
        }

Recommendation

For an full example check out the blog post: An Recommendation for creating Data Form Dialogs in SAPUI5

xml binding
When binding a aggregation in your xml view you can define a groupId. Changes made via two-way binding will lead to OData requests that are bundled into the specified groupId.

items="{ path: '/MyEntitySet', parameters: { groupId: 'groupIdA' } }"

manual requests

  • callFunction
  • create
  • remove
  • update

Leave a Reply

Your email address will not be published. Required fields are marked *