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.
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 |
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)); } } } |
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
13 | |
11 | |
10 | |
9 | |
9 | |
7 | |
6 | |
5 | |
5 | |
5 |