Miscellaneous¶
Offline OData service is the mobile services component that transmits data between the back end (OData service) and the client offline store.
Best Practices for Defining Queries¶
- Use “
/EntitySetA
” and “/EntitySetB
” versus “/EntitySetA?$expand=EntitySetB
”
This best practice depends on the OData service and the data in those entity sets. A defining query with an $expand
can be broken up into multiple defining queries without $expand
only if the association in the metadata defines a referential constraint.
It is generally preferable to use $expand
in OData queries for relationships, but this may not always provide the best performance for Offline OData:
-
Lack of support for deltas with
$expand
The Offline OData service does not support OData service deltas for defining queries with$expand
directly. If a defining query contains an$expand
, there are two possibilities, with respect to deltas:- Using the Offline OData service delta computation.
- Disabling the Offline OData service delta computation causes a full download of the data.
-
Data duplication Sometimes an application requires more than one defining query to get all the data and relationships because their data does not form a tree rooted from a single entity set. In such a case, many defining queries may have to expand to the same entity sets, creating duplicate entities retrieved from the OData service. Splitting the defining queries up resolves this problem because each entity is downloaded only once, and the Offline OData service computes the relationships using the referential constraints.
-
Shared data You may have a set of data shared by all users but
referenceable
by user specific data. In this case, you want to separate the shared data into a separate defining query from the user specific data. The relationships between the shared data and the user defined data are computed by the Offline OData service using the referential constraints, however, download the shared data only once for all users, instead of for each user. -
$top
and$skip
Developers should not use$top
or$skip
in defining queries. It's better to control the amount of data retrieved from the OData service using$filter
or other back-end-specific means (such as based on the currently authenticated user). If the use of$top
and$skip
is intended to break up how much data the OData service can send at one time, then change the service to use server driven paging instead (that is, return next links). The developer is free to use$top
and$skip
when executing local queries.
Provisioning the Device¶
-
Multiple stores
An application can use multiple offline stores. A store can only be used for one OData service, and it is a best practice that only one store is used per OData service. Define the stores using
OfflineODataParameters
that are then passed to theOfflineODataProvider
.
Errors¶
Client may report various errors. Typical reasons for errors to consider include but not limited to:
- Incorrect service root
- Incorrect defining queries
- Incorrect user input (resulting in invalid data in requests)
- Incorrect back end configuration in the mobile services
- Incorrect application configuration in the mobile services
- Back end OData service going down
- SAP Mobile Services going down
- Connectivity between mobile services and back end being unstable
When errors happen during upload and download, you should check mobile service log as well as ErrorArchive
on the client to diagnose the issue and figure out the resolution.
If any error happens during the initial download of data (opening the offline store for the first time), the offline store will automatically clean up the erroneous state/data, allowing the offline application to start over. In this case you should check error message reported by the client or mobile services log in order to correct the issue (for example, the client is using incorrect service root or defining queries).
Keep OAuth Token Valid During Synchronization¶
The OAuth tokens are expected to remain valid for the entire synchronization lifecycle. If the tokens become invalid during the sync, calling the backend fails in many SSO scenarios. This causes the whole synchronization to fail. This is particularly important when the synchronization takes a long time to finish.
Application developers now have an option to check the token's validity and refresh the access token if required before starting the synchronization.
// Note: Create this function and call it before each sync to refresh access token if required
private fun refreshToken() {
// Host URL used to look up access token
val host = FlowContextRegistry.flowContext.appConfig!!.serviceUrl
// Check token validity, suppose synchronization takes at least 10 minutes to finish
val expirationTime = OAuth2Helper.getAccessTokenExpirationTime(host)
if (Instant.now().plusSeconds(10 * 60).isAfter(expirationTime)) {
// Refresh the access token if the validity period is too short
runBlocking {
OAuth2Helper.renewOAuth2Token(host, false)
}
} else {
// Token validity is long enough
}
}
// Note: Create this method and call it before each sync to refresh access token if required
private void refreshToken() {
// Host URL used to look up access token
String host = FlowContextRegistry.getFlowContext().getAppConfig().getServiceUrl();
// Check token validity, suppose synchronization takes at least 10 minutes to finish
Instant expirationTime = OAuth2Helper.getAccessTokenExpirationTime(host);
if (Instant.now().plusSeconds(10 * 60).isAfter(expirationTime)) {
// Refresh the access token if the validity period is too short
OAuth2Helper.renewOAuth2Token(host, false);
} else {
// Token validity is long enough
}
}
See OAuth2Helper for Kotlin documentation or OAuth2Helper for Java documentation.