<updated>Oct 28, 2014</updated>
Hello everyone,
Back to the blog :-)
Now that we have went all the way through the 10 blogs, general understanding of the OData API has been deployed on top of our brains.
From now on, we'll discuss some gotchas to watch out. As all those information are "as it is", please expect constant update in the blog, I'll put the timestamp explicitly whenever some important update come in in the future.
Throughout this blog I would like to cover bits and pieces around SODataOfflineStore.
Removing the offine store
In the blog #06, we learned how to create an offline store. We haven't discussed yet how to remove it... Here's the code to name the offline store, which is required for removal step later. The storeName property is optional for SODataOfflineStoreOptions instance. If it is not set when opening the store, it chooses a default name.
01 SODataOfflineStore *offlineStore = [[SODataOfflineStore alloc] init]; 02 SODataOfflineStoreOptions *options = [[SODataOfflineStoreOptions alloc] init]; 03 options.storeName = @"MyStore"; 04 ..
And the code below is about how to remove the physical store from the file system. If you don't set the storeName during the creation, the default value will be used without the property value. As written in the line #04, the store must to be closed before the removal.
Note: For security, you should be closing your store instances whenever you do not need them (e.g. via applicationDidEnterBackground:, when you app goes to the background). Once it is closed, it can be open by openStoreWithOptions:error: method (e.g. via applicationWillEnterForeground:).
01 NSError *error = nil; 02 SODataOfflineStoreOptions *options = [[SODataOfflineStoreOptions alloc] init]; 03 options.storeName = @"MyStore"; 04 [offlineStore closeStoreWithError:&error]; 05 [SODataOfflineStore RemoveStoreWithOptions:options error:&error]; 06 if (error) { 07 // store removal failed 08 } else { 09 // store removal succeeded 10 }
Defining Request
In the blog #06 and #07, we learned what Defining Request is and how to define it in the code. You might encounter runtime error during the offline store instance creation - a few things to keep in mind:
- Entity relationships
In order for entity relationships to be available (e.g. "CarrierCollection('CO')/carrierFlights" - the relationship from one entity to another) on the client we need to have one of two things:
Option 1) Use $expands in your defining requests
Option 2) Inside OData services, implement a set of referential constraints between the two entity types
Option 1 - The $expand syntax is to name the navigation property that you want to expand, most OData producers do support $expand.
Note: The defining requests have to be non-overlapping with the data they download. For example, if my defining request code is written in this way in order to navigate from Carrier entity to Flight entity (the data here is well known FLIGHT data example in NetWeaver Gateway):
01 options.definingRequests[@"req1"] = @"/FlightCollection"; 02 options.definingRequests[@"req2"] = @"/CarrierCollection?$expand=carrierFlights";
The first defining request downloads it directly, while the second downloads it again with the additional flight data. This is causing the server to report duplicate entry errors. It works as expected after removing the first defining request and only has the second.
01 //options.definingRequests[@"req1"] = @"/FlightCollection"; 02 options.definingRequests[@"req2"] = @"/CarrierCollection?$expand=carrierFlights";
Option 2 - A referential constraint is extra information attached to an Association (or relationship) that says how the two entities are related. In OData Metadata, you should be able to find the <ReferentialConstraint> tags if it is implemented in OData services. If these are supplied, the relationships between entities is defined by the properties directly and MobiLink can use that to build up the links behind the scenes. The benefit of this approach is in case $expand can't be used, we can go to this option.
So if the OData service implements both $expand and referential constraint for the entity relationship between Customers and Orders, both do the same job from the client perspective.
01 options.definingRequests[@"req"] = @"/Customers?$expand=Orders";
01 options.definingRequests[@"req1"] = @"/Customers"; 02 options.definingRequests[@"req2"] = @"/Orders";
[There is a bit of a description of referential constraints in section 10.4 of Common Schema Definition Language (CSDL). Essentially, referential constraints are OData metadata details that can be supplied in order to make OData properties act more like relational database foreign keys.]
- OData collection times out with HTTP 500 error
You might encounter the runtime error during the offline store creation, simply because the OData collection you're trying to fetch is too big - you can copy & paste the OData endpoint URL in the web browser and see if it shows 500 timeout error. The issue in this case is a problem on the server-side. Our HTTP requests for data were timing out because the backend producer was taking too long to query the data and encode it as OData.
In this case we should consider using server side paging on OData producer.
There are two types of paging in OData – server side and client side.
Client side paging is driven by having a $top value and then incrementing the $skip values for each request (e.g. $top=100&$skip=0 for first request, then $top=100&$skip=100 for second request etc.) This type of paging will not help with populating the database in the offline store because the defining requests are fixed. (Of course, you can use $top or $skip to make requests for small amounts of data to the local store after the store has been populated.)
In server side paging, even if you request the entire big OData collection, the server will only return a portion of the results, but provide a “next link” info, which can be followed to get the next portion and so on. When the MobiLink is populating the local store it knows how to follow these next links. Server side paging via next links is OData Version 2.0 feature.
Offline OData Version Support info
Is here!
OData Query Options supported by SAP NetWeaver Gateway
is here!
Okie that's all for the blog this time. I'll cover some other practical topic in the next blog...
See you in the next blog,
Ken