Professional Documents
Culture Documents
Mobile Apps
Public
Speakers
The information in this presentation is confidential and proprietary to SAP and may not be disclosed without the permission of
SAP. Except for your obligation to protect confidential information, this presentation is not subject to your license agreement or
any other service or subscription agreement with SAP. SAP has no obligation to pursue any course of business outlined in this
presentation or any related document, or to develop or release any functionality mentioned therein.
This presentation, or any related document and SAP's strategy and possible future developments, products and or platforms
directions and functionality are all subject to change and may be changed by SAP at any time for any reason without notice.
The information in this presentation is not a commitment, promise or legal obligation to deliver any material, code or functionality.
This presentation is provided without a warranty of any kind, either express or implied, including but not limited to, the implied
warranties of merchantability, fitness for a particular purpose, or non-infringement. This presentation is for informational
purposes and may not be incorporated into a contract. SAP assumes no responsibility for errors or omissions in this
presentation, except if such damages were caused by SAPs intentional or gross negligence.
All forward-looking statements are subject to various risks and uncertainties that could cause actual results to differ materially
from expectations. Readers are cautioned not to place undue reliance on these forward-looking statements, which speak only
as of their dates, and they should not be relied upon in making purchasing decisions.
Offline OData allows you to build an offline-enabled applications using the same APIs you
would for a purely-online application
Myth: This makes adding offline capability as easy as writing a few lines of code
Reality: There are design considerations that are very important to understand when writing an
offline application. Among them:
Conflict Resolution/Error Handling
Performance
Data Volume
Transaction Behavior (Batched instead of Immediate)
Temporary, Client-side-only Keys
Flush
Uploads the operations in the request queue to the server
Resolves local IDs to real IDs
Records error information and puts affected entities into the error state
The flush does not download new data from the backend to the entity store
Refresh
Downloads data from the backend so that it matches on the client
Resolves local entities/relationships with backend data
Obviously all the data can be sent during a refresh but in general that will be too expensive. A
better approach is to only send what has changed (the delta).
To maximize performance, the OData delta protocol SHOULD be implemented by the OData
backend to ensure only the changes are sent to the SMP/HCPms server.
By default, if no OData deltas are provided by the OData backend, SMP/HCPms will compute
the delta to be sent to the client.
This is an expensive and generic approach but a workable solution in some cases
A defining request that returns the same data for all clients (or a group of clients) should be
marked as shared.
Shared defining requests are cached in the SMP/HCPms server so that all clients can retrieve
the shared data from the cache instead of all going to the backend.
Marking a defining request as shared is as simple as uploading an INI file with the defining
request marked with is_shared_data=Y.
The INI file can also be used to configure how often the shared data should be updated.
Taking advantage of shared data will reduce the load on the OData backend and therefore can
result in an overall improvement on performance.
Use case
The app needs relationships while offline
To improve refresh performance, the use of OData backend deltas is desirable
There is a large amount of shared data and it needs to be related to non-shared data
Problems
OData V2 does not support deltas when $expand are used in defining requests
Shared and non-shared data needs to be separated in the defining requests
Solution
All associations in the $metadata (except many-to-many) can expose a referential constraint
Offline OData can build the relationships for the Offline store using referential constraints
Therefore, expose referential constraints in the $metadata and break up the defining requests
<Association Name="Customer">
Original: <End Multiplicity="*" Role="OrderEnd" Type="SAP.Order"/>
~/Customers?$expand=Orders/OrderItems/Product <End Multiplicity="1" Role="CustomerEnd" Type="SAP.Customer"/>
<ReferentialConstraint>
<Principal Role="CustomerEnd">
<PropertyRef Name="ID"/>
Separated after exposing referential </Principal>
constraints: <Dependent Role="OrderEnd">
<PropertyRef Name="CustomerID"/>
~/Customers </Dependent>
</ReferentialConstraint>
~/Orders </Association>
~/OrderItems <Association Name="Product">
<End Multiplicity="*" Role="ItemEnd" Type="SAP.OrderItem"/>
~/Products <End Multiplicity="1" Role="ProductEnd" Type="SAP.Product"/>
<ReferentialConstraint>
<Principal Role="ProductEnd">
<PropertyRef Name="ID"/>
</Principal>
<Dependent Role="ItemEnd">
<PropertyRef Name="ProductID"/>
</Dependent>
</ReferentialConstraint>
</Association>
Use case
The application needs to display the data to the end user
Problems
The device can only display a limited amount of data on the screen at one time
Loading all entities into memory at one time is not feasible
Solution
Read the data in pages
Use client-driven paging; add $top and $skip to the local queries OR
Use server-driven paging; specify the page size (using a Prefer odata.maxpagesize header or store option) and
the SDK will return a next link if there is more data
Use case
The app needs to have the ability to create new entities while offline
While offline, both the newly created entities and entities downloaded from the server need to be both read and
modified
Problems
It can be difficult for applications to assign unique key values
In many cases, key values are assigned by the backend during the POST operation
It is technically valid in some cases for OData backends to ignore key values specified by the client in the POST
body and assign its own key value
...
{
"__metadata": {
"uri": "Customers(193)",
"type": "SAP.Customers
...
},
"ID": 193,
"Surname": "Lechner",
"GivenName": "Sami",
...
},
...
{
"__metadata": {
"uri": "Customers(lodata_sys_edt=X'5CD949C1F0FC4FF0AA06F8C9C5C8D7C200000000')",
"type": "SAP.Customers",
...
},
"@com.sap.vocabularies.Offline.v1.islocal": true,
"ID": null,
"Surname": "Borges",
"GivenName": "Matt",
...
}
...
Code to save the URL when reading entities: Code to use the saved URL when updating the
entity:
var request = {
headers : oHeaders,
for( var i = 0; i < data.results.length; i++ ) { // Use the edit link that was previously saved
// Save the edit links returned by the SDK requestUri : editLinks[ currEntityIdx ],
editLinks.push( data.results[ i ].__metadata.uri ); method : "PATCH",
data : {
// Code to display the entity // Updated properties for the entity
... ...
} }
};
OData.request( request, patchSuccessCallback, errorCallback );
Use case
The app needs to create multiple related new entities while offline
The involved relationships have a to many end
Problem
Offline OData does not support deep insert operations when at least one end of the relationships is to many
Solution
The OData V2 standard supports six ways for creating and modifying relationships (a deep insert is one of those
six ways)
Offline OData supports all methods of creating and modifying relationships offline with the exception of deep
inserts in the to many case
An equivalent way to create multiple new entities that are related is by using Content-ID referencing in a batch
request
var body = {
__batchRequests: [
{
__changeRequests: [
{
requestUri: "Customers",
method: "POST",
headers: { "Content-ID": "1 },
data: { "GivenName": "Matt", "Surname": "Borges }
},
{
requestUri: "$1/Orders",
method: "POST",
data : { "ProductID" : productID, "Quantity" : 1 }
}
]
}
]
};
When OData requests submitted by Offline OData as part of the flush fail, the errors are
returned to the device and the entities involved in the failed request are put into an error state.
The SMP/HCPms server will not send subsequent requests that depend on a failed request.
When the flush completes, the errors that occurred are available to the app in a special entity
set called the ErrorArchive, which can be queried just like any other entity set.
After the flush it, is up to the app to fix any errors. This is typically done by issuing subsequent
OData request(s) to fix the problem.
When a flush is called with failed requests in the queue, a merge algorithm is run to merge the
failed requests with new requests referencing the same entity to attempt to create requests
without the errors.
When a flush operation itself fails (not the requests in the flush), what operations were sent and
completed by the OData server is also lost.
As a result, in the next flush all operations need to be resent to the OData backend.
Repeatable requests is a feature that OData servers can support to prevent the same operation
(for example, a POST) from being executed more than once.
Repeatable requests is not part of the OData standard directly but is a OData standards
committee note.
Repeatable requests is important for all OData backends, but in particular for those used with
Offline OData.
Public
SAP TechEd Online
No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP SE or an SAP affiliate company.
SAP and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP SE (or an SAP affiliate
company) in Germany and other countries. Please see http://www.sap.com/corporate-en/about/legal/copyright/index.html for additional trademark information and notices.
Some software products marketed by SAP SE and its distributors contain proprietary software components of other software vendors.
These materials are provided by SAP SE or an SAP affiliate company for informational purposes only, without representation or warranty of any kind, and SAP SE or its
affiliated companies shall not be liable for errors or omissions with respect to the materials. The only warranties for SAP SE or SAP affiliate company products and
services are those that are set forth in the express warranty statements accompanying such products and services, if any. Nothing herein should be construed as
constituting an additional warranty.
In particular, SAP SE or its affiliated companies have no obligation to pursue any course of business outlined in this document or any related presentation, or to develop
or release any functionality mentioned therein. This document, or any related presentation, and SAP SEs or its affiliated companies strategy and possible future
developments, products, and/or platform directions and functionality are all subject to change and may be changed by SAP SE or its affiliated companies at any time
for any reason without notice. The information in this document is not a commitment, promise, or legal obligation to deliver any material, code, or functionality. All forward-
looking statements are subject to various risks and uncertainties that could cause actual results to differ materially from expectations. Readers are cautioned not to place
undue reliance on these forward-looking statements, which speak only as of their dates, and they should not be relied upon in making purchasing decisions.