Skip to Content

Creating hierarchical data using Content-ID Referencing in a Change Set (Batch Request)

In the previous blog on deep inserts, I had mentioned that there is a limitation in OData specifications that does not allow deep inserts 1:N for Offline applications.  I also talked about a workaround that allows us to persist property values of the parent and child entities in the datavault when the device is offline.  Later when the device is online, we can perform a deep insert 1:N followed by a refresh of the Offline Store.

There is yet another alternative to creating hierarchical data.  This can be accomplished using Content-ID referencing in a change set (batch request).  Please refer to the OData specifications on Referencing Requests in a Change Set.

In our example, we will use the universally available OData Service found in http://services.odata.org.  Since this involves updating the backend data, use the link to create a full access (Read-Write) service.

Difference between deep insert and Content-ID referencing in a change set (batch request) ?

There are quite a few similarities between deep insert and Content-ID referencing in a change set (batch request).  Both these approaches can be used to insert hierarchical data.  The table below describes some of the differences between deep insert and Content-ID referencing in a change set (batch request).

Deep Insert

Content-ID referencing in a change set (batch request)


Deep insert allows creating hierarchical data using a single payload in a single request

Multiple requests are grouped into a single request

Deep Insert is somewhat easier. The single payload in the POST request is in the same format as that of a GET request with $expand

If a MIME part representing an Insert request within a ChangeSet includes a Content-ID header, then the new entity represented by that part may be referenced by subsequent requests within the same ChangeSet by referring to the Content-ID value prefixed with a “$” character.

Most OData providers support deep insert – including Integration Gateway

Integration Gateway does not support Content-ID referencing in a batch request.  However, there are other 3rd party OData producers that support Content-ID referencing in a change set.

Limitation in OData specification does not allow for deep inserts 1:N for Offline applications

No such limitation. Hierarchical data can be inserted in both Online and Offline applications

Creating hierarchical data with 1:N relationship using Content-ID referencing in a change set (batch request – Online)

As in the previous blog, the first step is to create the parent entity.  PropertyCreationMode.All indicates that you will be supplying all the values for the properties.  If you do not supply values for any of the optional properties, the default value will be used.  Note that you also want to call the AllocateNavigationProperties method to establish the navigation properties in the parent entity.  The following code snippet creates a local parent entity and sets the values for the properties.

var parentEntity = new SAP.Data.OData.Online.ODataEntity(“ODataDemo.Category”);

parentEntity.SetResourcePath(“Categories”, “Categories”);

Store.AllocateProperties(parentEntity, PropertyCreationMode.All);

SharedContext.Context.OnlineStore.AllocateNavigationProperties(parentEntity);

parentEntity.Properties[“ID”].Value = 3;

parentEntity.Properties[“Name”].Value = “Home Goods”;

The next step is to create the child entities.  The following code snippet creates 2 child entities and sets the values for the properties.

var childEntity1 = new SAP.Data.OData.Online.ODataEntity(“ODataDemo.Product”);

childEntity1.SetResourcePath(“Products”, “Products”);

SharedContext.Context.OnlineStore.AllocateProperties(childEntity1, SAP.Data.OData.Store.PropertyCreationMode.All);

childEntity1.Properties[“ID”].Value = 501;

childEntity1.Properties[“Name”].Value = “Tennis racket”;

childEntity1.Properties[“Description”].Value = “Prince O-Shark Tennis racket”;

childEntity1.Properties[“ReleaseDate”].Value = DateTime.Now;

childEntity1.Properties[“Rating”].Value = 5;

childEntity1.Properties[“Price”].Value = 174.99m;

var childEntity2 = new SAP.Data.OData.Online.ODataEntity(“ODataDemo.Product”);

childEntity1.SetResourcePath(“Products”, “Products”);

SharedContext.Context.OnlineStore.AllocateProperties(childEntity2, SAP.Data.OData.Store.PropertyCreationMode.All);

childEntity2.Properties[“ID”].Value = 502;

childEntity2.Properties[“Name”].Value = “Tennis shoes”;

childEntity2.Properties[“Description”].Value = “Prince Invisible Shoes”;

childEntity2.Properties[“ReleaseDate”].Value = DateTime.Now;

childEntity2.Properties[“Rating”].Value = 5;

childEntity2.Properties[“Price”].Value = 124.99m;

The next step is to group the requests into a single request.  This is done by creating a change set and adding the requests to the change set.  The request for the parent entity contains the Content-ID header.   Subsequent child requests in the same Change Set reference the Content-ID prefixed by the “$” character.  The following snippet of code builds the batch request with the Change Set containing insert requests for both the parent and the child entities.

var contentId = 1;

this.ChangeSet = new ODataRequestChangeSet();

this.BatchRequest = newODataRequestParametersBatch();

var parentItem = new ODataRequestParametersSingle(“Categories”, RequestMode.Create, parentEntity);

parentItem.ContentId = contentId.ToString();

this.ChangeSet.Add(parentItem);

this.ChangeSet.Add(new ODataRequestParametersSingle(“$” + contentId + “/Products”, RequestMode.Create, childEntity1));

this.ChangeSet.Add(newODataRequestParametersSingle(“$” + contentId + “/Products”, RequestMode.Create, childEntity2));

this.BatchRequest.Add(ChangeSet);

The last step is to submit the POST request.  The following snippet of code submits the POST request and also parses the response.

this.ResponseList = ((IReadOnlyCollection<IODataResponseBatchItem>)((IODataResponseBatch)((await SharedContext.Context.OnlineStore.ScheduleRequest(this.BatchRequest).Response))).Responses);

ParseResponse();

public void ParseResponse()

{

   foreach (var item in ResponseList)

   {

      if (item is IODataResponseChangeSet)

      {

         foreach (var element in ((ODataResponseChangeSet)item).Responses)

         {

            System.Diagnostics.Debug.WriteLine(“Status Code: “ + element.Headers[“http.code”].ElementAt(0));

         }

   }

}

Creating hierarchical data with 1:N relationship using Content-ID referencing in a change set (batch request – Offline)

The steps involved in creating hierarchical data with 1:N relationship using Content-ID referencing in a change set (batch request) for an Offline application is identical to the steps outlined in the previous section for an Online application.  The only difference is that you will use the Offline Store instead of the Online Store.  You will also need to call Flush and Refresh later when the device becomes online.

The following code snippet submits the POST request for the Offline Store.

this.ResponseList = ((IReadOnlyCollection<IODataResponseBatchItem>)((IODataResponseBatch)((await SharedContext.Context.OfflineStore.ScheduleRequest(this.BatchRequest).Response))).Responses);

When the device is online, simply call the Flush and the Refresh method to submit local changes to the backend and to retrieve data from the backend.

await SharedContext.Context.OfflineStore.ScheduleFlushQueuedRequestsAsync();

await SharedContext.Context.OfflineStore.ScheduleRefreshAsync();

Please find attached the source code for a sample Windows application that creates hierarchical data using Content-ID referencing in a change set (batch request).

In the next blog, I will talk about cancelling asynchronous request in SAP Mobile Platform SDK.

To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. Jeff Lau

    Hi Milton Chandradas

    This was very informative.


    We have tested this out and the creation of a new Parent and multiple new children for an offline store works fine.


    However we are having issues with creating multiple new children (EntitySet) and then associating it with an existing parent. If it was just one child to an existing parent it is fine, but when it is an EntitySet we get an error stating deep insert is not supported.

    Any ideas?

    Thanks

    Jeff

    (0) 
    1. Michael Appleby

      Hi Jeff,

      Please create a new Discussion marked as a Question.  The Comments section of a Blog (or Document) is not the right vehicle for asking questions as the results are not easily searchable.  Once your issue is solved, a Discussion with the solution (and marked with Correct Answer) makes the results visible to others experiencing a similar problem.  If a blog or document is related, put in a link.

      NOTE: Getting the link is easy enough for both the author and Blog.  Simply MouseOver the item, Right Click, and select Copy Shortcut.  Paste it into your Discussion.  You can also click on the url after pasting.  Click on the A to expand the options and select T (on the right) to Auto-Title the url.

      Thanks, Mike (Moderator)

      SAP Technology RIG

      (0) 
    2. Milton Chandradas Post author

      Jeff,

      If there is an existing Parent, then it no longer falls under the deep insert category.  You are simply inserting multiple rows (child entities).  Since the Parent already exists, you already know the ID that needs to be referenced to make the relationship. 

      (0) 
      1. Jeff Lau

        Hi Milton Chandradas

        Thanks for the response. I have created the question here: Adding an entity to an entity set

        Just to clarify the existing parent I refer to was created using the method in this approach and it has not been pushed to the server. i.e. created the parent + some child entities, before flushing back to the server we wanted to do some additional updates to these locally created entities.

        By the sounds of your explanation the above should be fine though.

        (0) 

Leave a Reply